Le stockage de table Azure renvoie 400 demandes incorrectes

119

J'ai exécuté cela en mode débogage et j'attache une image avec les détails de l'exception. Comment puis-je savoir ce qui ne va pas? J'essayais d'insérer des données dans un tableau. Azur ne peut pas me donner plus de détails?

Obs: le stockage est sur Windows Azure et non sur ma machine. Les tables ont été créées, mais j'obtiens cette erreur lors de l'insertion de données

entrez la description de l'image ici

// Retrieve the storage account from the connection string.
Microsoft.WindowsAzure.Storage.CloudStorageAccount storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=***;AccountKey=***");

// Create the table client.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

// Create the table if it doesn't exist.
CloudTable table = tableClient.GetTableReference("EmployeeOnlineHistory");
table.CreateIfNotExists();

et voici le code d'insertion:

public static void SetStatus(Employee e, bool value)
{
    try
    {
        // Retrieve the storage account from the connection string.
        Microsoft.WindowsAzure.Storage.CloudStorageAccount storageAccount = Microsoft.WindowsAzure.Storage.CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=###;AccountKey=###");

        // Create the table client.
        CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

        // Create the CloudTable object that represents the "people" table.
        CloudTable table = tableClient.GetTableReference("EmployeeOnlineHistory");

        // Create a new customer entity.

        if (value == true)
        {
            EmployeeOnlineHistory empHistory = new EmployeeOnlineHistory(e.Id);
            empHistory.IsOnline = true;
            empHistory.OnlineTimestamp = DateTime.Now;
            TableOperation insertOperation = TableOperation.Insert(empHistory);
            table.Execute(insertOperation);
        }
        else
        {
            TableQuery<EmployeeOnlineHistory> query = new TableQuery<EmployeeOnlineHistory>()
                .Where(TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, e.Id.ToString()));
            EmployeeOnlineHistory entity = table.ExecuteQuery(query).Take(1).FirstOrDefault();

            if ((entity!=null)&&(entity.IsOnline))
            {
                entity.IsOnline = false;
                entity.OfflineTimestamp = DateTime.Now;
                entity.OnlineTime = (entity.OfflineTimestamp - entity.OnlineTimestamp);
                TableOperation updateOperation = TableOperation.Replace(entity);
                table.Execute(updateOperation);
            }
            else
            {
                EmployeeOnlineHistory empHistory = new EmployeeOnlineHistory(e.Id);
                empHistory.IsOnline = false;
                empHistory.OfflineTimestamp = DateTime.Now;
                TableOperation insertOperation = TableOperation.Insert(empHistory);
                table.Execute(insertOperation);
            }
        }
    }
    catch (Exception ex)
    {
        //var details = new System.IO.StreamReader(((Microsoft.WindowsAzure.Storage.StorageException)ex)..Response.GetResponseStream()).ReadToEnd();
        LogFile.Error("EmployeeOnlineHistory.setStatus",ex);
    }
}
Ryan
la source
Cette image n'aide pas vraiment, mis à part la confirmation de l'erreur 400. Est-ce que "serait" utile est de montrer le code que vous avez exécuté qui a abouti à la mauvaise demande: comment vous avez configuré le client de stockage, comment vous avez configuré la table, puis à insérer, etc.
David Makogon
J'ai copié-collé le code. J'espère que cela aide
Ryan
Il serait utile que vous disiez lequel des nombreux cas échoue. De plus, vous définissez apparemment certaines propriétés en dehors de ce code (par exemple, PartitionKey et RowKey), il serait donc utile de savoir ce qu'elles sont et ce sur quoi elles sont définies.
Brian Reischl
J'ai remarqué que lorsque l'exception est lancée en premier, il n'y a pas d'option "Afficher les détails", mais lorsque vous continuez le débogage et que le flux retourne à l'appelant (où l'exception réapparaît), vous pouvez voir l'option Afficher les détails. De là, vous pouvez utiliser la réponse de @Juha Palomäki pour trouver l'erreur
raghav710

Réponses:

149

400 Une erreur signifie qu'il y a un problème avec la valeur de l'une de vos propriétés. Une façon de le savoir est de suivre la demande / réponse via Fiddler et de voir les données réelles envoyées au stockage Windows Azure.

Prenant une supposition sauvage, je suppose en jetant un coup d'œil rapide à votre code que dans votre modèle vous avez des propriétés de type Date / Heure (OfflineTimestamp, OnlineTimestamp) et j'ai observé que dans certains scénarios, l'un d'entre eux est initialisé avec la valeur par défaut qui est " DateTime.MinValue ". Veuillez noter que la valeur minimale autorisée pour un attribut de type Date / Heure est le 1er janvier 1601 (UTC) dans Windows Azure [http://msdn.microsoft.com/en-us/library/windowsazure/dd179338.aspx] . Veuillez voir si ce n'est pas le cas. Si tel est le cas, vous pouvez créer des champs de type nullable afin qu'ils ne soient pas remplis avec les valeurs par défaut.

Jetez également un œil à la réponse de Juha Palomäki ci-dessous ... il y a parfois un message légèrement plus utile dans l'exception où il suggère (RequestInformation.ExtendedErrorInformation.ErrorMessage)

Contributions arrêtées
la source
260
Pour l'amour de Dieu, si quelqu'un de l'équipe Azure lit ceci, veuillez faire en sorte que le SDK renvoie plus d'informations que l'erreur 400 Bad Request. Je n'ai aucune idée pourquoi le DateTime dans le stockage de table ne peut pas avoir la même date minimale que l'objet .NET DateTime, mais j'ai perdu une bonne journée sur celui-ci. Au moment où je suis arrivé à quelle propriété causait le problème, je suis également tombé sur cela, ce qui a aidé. Maintenant, avant d'insérer / mettre à jour un modèle avec un DateTime pour le stockage de table, je dois exécuter des vérifications sur toutes les propriétés DateTime. PAS idéal ...
Michael
8
Tant que nous y sommes, vous ne pouvez pas non plus avoir de propriété enum. J'ai dû convertir une propriété en entier
Martin
15
Apparemment, les noms de table ne peuvent pas non plus avoir de traits d'union. Il m'a fallu une heure pour comprendre cela.
Amogh Natu
4
Les noms de table ne peuvent pas non plus avoir de traits de soulignement ... c'est pourquoi je suis ici
Quango
2
J'imagine que RowKey n'est pas initialisé avec une chaîne vide car il s'agit de la valeur de recherche principale et seulement de la colonne indexée ... c'est pour vous rappeler de la remplir, j'aurais pensé ... ce n'est que ma supposition cependant ... En ce qui concerne les noms des tables vont .. lisez ceci ... blogs.msdn.microsoft.com/jmstall/2014/06/12/…
dreadeddev
129

Le StorageException contient également des informations un peu plus détaillées sur l'erreur.

Archiver le débogueur: StorageException.RequestInformation.ExtendedInformation

entrez la description de l'image ici

Juha Palomäki
la source
6
Pourquoi cette information n'est-elle pas une exception de niveau supérieur?
Wilko van der Veen
Pour moi, cela a mis en évidence .. "Ajouter le blob non pris en charge par l'émulateur" .. FML
Michiel Cornille
The specifed resource name contains invalid characters.le nom de ma table contenait des tirets ... tout comme mes noms de file d'attente ... soupir. Espérons que la recherche ramènera cela pour plus de gens! voir: stackoverflow.com/questions/45305556/…
Nateous
55

Dans mon cas, c'était une barre oblique dans le RowKey .

J'ai également reçu un «OutOfRangeInput - L'une des entrées de demande est hors de portée. erreur lors de la tentative d'ajout manuel via l'émulateur de stockage.

Caractères interdits dans les champs clés

Les caractères suivants ne sont pas autorisés dans les valeurs des propriétés PartitionKey et RowKey :

  • Le caractère barre oblique ( / )
  • Le caractère antislash ( \ )
  • Le caractère dièse ( # )
  • Le caractère de point d'interrogation ( ? )
  • Caractères de contrôle de U + 0000 à U + 001F , y compris:
    • Le caractère de tabulation horizontale ( \ t )
    • Le caractère de saut de ligne ( \ n )
    • Le caractère de retour chariot ( \ r )
    • Caractères de contrôle de U + 007F à U + 009F

http://msdn.microsoft.com/en-us/library/dd179338.aspx

J'ai écrit une méthode d'extension pour gérer cela pour moi.

public static string ToAzureKeyString(this string str)
{
    var sb = new StringBuilder();
    foreach (var c in str
        .Where(c => c != '/'
                    && c != '\\'
                    && c != '#'
                    && c != '/'
                    && c != '?'
                    && !char.IsControl(c)))
        sb.Append(c);
    return sb.ToString();
}
Shawn McGough
la source
4
C'était aussi mon problème. Votre méthode d'extension fonctionne comme un champion!
James Wilson
1
J'ai adoré la méthode d'extension. M'a sauvé.
Newton Sheikh
Autre réponse donnée ici qui fait qu'une expression
régulière
J'ai corrigé ça pour moi. J'ai eu une barre oblique. Cela semblait être un bon caractère pour une pseudo clé composée.
richard
Cette méthode d'extension ne supprime pas plusieurs caractères non autorisés. Par exemple: espace, "(", ")" ... docs.microsoft.com/en-us/rest/api/storageservices
Tiago Andrade e Silva
6

J'ai rencontré le même problème mais la raison dans mon cas était due à la taille. Après avoir fouillé dans les propriétés d'exception supplémentaires (RequestInformation.ExtendedErrorInformation), j'ai trouvé la raison:

ErrorCode: PropertyValueTooLarge ErrorMessage: la valeur de la propriété dépasse la taille maximale autorisée (64 Ko). Si la valeur de la propriété est une chaîne, elle est encodée en UTF-16 et le nombre maximal de caractères doit être de 32 Ko ou moins.

Nibras Manna
la source
5

Eh bien, dans mon cas, j'essayais de faire ceci:

CloudBlobContainer container = blobClient.GetContainerReference("SessionMaterials");
await container.CreateIfNotExistsAsync();

à cause de ContainerName SessionMaterials(comme une habitude d'écrire dans Pascal Case et Camel Case: D), cela provoquait 400 mauvaises requêtes. Alors, je dois juste y arriver sessionmaterials. et cela a fonctionné.

J'espère que cela aide quelqu'un.

PS: - Vérifiez simplement la réponse http d'exception ou utilisez un fiddler pour capturer la demande et la réponse.

Jawand Singh
la source
3

dans mon cas: le nom du conteneur était en majuscule. il y a des limitations lors de l'utilisation de caractères. entrez la description de l'image ici

Ravi Anand
la source
Cela vaut également pour les noms de propriétés de table.
Iain Ballard
3

Parfois, c'est parce que votre partitionKeyou rowKeyestNULL

(c'était le cas pour moi)

Maroine Abdellah
la source
1

Une documentation de MS sur tous les codes d'erreur de service de table peut être trouvée ici

huha
la source
1

J'ai eu la même erreur BadRequest (400), à la fin, je remplis manuellement:

entrez la description de l'image ici

Et a travaillé pour moi. J'espère que cela t'aides!

Gatsby
la source
Cette réponse est correcte. J'ai perdu environ une heure et cela supprime que même Timestampdoit être généré manuellement. C'est vraiment agaçant.
Roman Koliada
0

J'ai également fait face au même genre de problème. Dans mon cas, la valeur PartitionKey n'a pas été définie, donc par défaut, la valeur PartitionKey était nulle, ce qui a entraîné une Object reference not set to an instance of an object.exception

Vérifiez si vous fournissez les valeurs appropriées pour PartitionKey ou RowKey, vous pouvez être confronté à un tel problème.

Dilip Nannaware
la source
0

J'ai réparé mes affaires et ça a bien fonctionné

Mes cas:

  1. La clé de ligne n'est pas au format correct (400).
  2. La combinaison de partitionkey et de rowkey n'est pas unique (409).
Kurkula
la source
0

Je recevais une 400 Bad Request car j'utilisais ZRS (Zone Redundant Storage) et Analytics n'est pas disponible pour ce type de stockage. Je ne savais pas que j'utilisais Analytics.

J'ai supprimé le conteneur de stockage et recréé en tant que GRS et maintenant cela fonctionne très bien.

Aidan
la source
0

Je recevais une (400) mauvaise demande, StatusMessage: Bad Request, ErrorCode: OutOfRangeInput lorsque l'entité avait une propriété DateTime non définie (= DateTime.MinValue)

Stig
la source
0

Dans mon cas: j'ai inclus des métadonnées blob avec un nom de balise contenant un trait d'union.

var blob = container.GetBlockBlobReference(filename);
blob.Metadata.Add("added-by", Environment.UserName);
//.. other metadata
blob.UploadFromStream(filestream);

Le tiret "added-by"était le problème, et plus tard RTFM m'a dit que les noms de balises doivent être conformes aux conventions d'identificateur C #.

Réf: https://docs.microsoft.com/en-us/azure/storage/blobs/storage-properties-metadata

Le soulignement fonctionne très bien.

Steve Friedl
la source
0

Dans mon cas, je ne devrais pas ajouter PartitionKey et Rowkey dans ma classe d'entité. Cela devrait provenir de la classe de base. Ci-dessous fonctionnerait simplement.

public class TableRunLogMessage:TableEntity
{
      public string status { get; set; }
      public long logged { get; set; }


      public TableRunLogMessage() { }
}
joyeux
la source
0

Si vous utilisez NodeJS et que vous êtes tombé sur ce post, seulement pour constater que vous n'obtenez pas ces belles informations détaillées dans votre objet d'erreur; vous pouvez utiliser un proxy pour obtenir ces détails. Cependant, puisque personne ne mentionne ici COMMENT utiliser un proxy.

Le moyen le plus simple avec NodeJS est de définir deux variables d'environnement:

NODE_TLS_REJECT_UNAUTHORIZED=0
This disables SSL checks so you can intercept your own SSL requests. This leaves you open to Man-in-The-Middle attacks and should NEVER make it to production, and I wouldn't even leave it in development for long. However, it will allow you to intercept the HTTP Requests.

HTTP_PROXY=http://127.0.0.1:8888
This sets node to utilize a proxy listening on your localhost at port 8888. Port 8888 is the default for Fiddler. Many other proxies default to 8080.

Si vous utilisez réellement C #, comme le fait l'auteur de cet article; vous pouvez simplement installer Fiddler et le configurer pour intercepter. Par défaut, il doit intercepter les requêtes. Vous devrez peut-être également faire confiance au certificat de Fiddler ou faire l'équivalent de "NODE_TLS_REJECT_UNAUTHORIZED = 0" de Node.

Doug
la source
0

J'ai reçu une réponse 400-BadRequest de l'API Azure Storage Account Table. Les informations d'exception ont montré que "Le compte auquel vous accédez ne prend pas en charge http.". J'ai pensé que nous devions utiliser https dans la chaîne de connexion lorsque "Transfert sécurisé requis" est activé dans la configuration du compte de stockage, comme indiqué dans l'image ci-dessous.entrez la description de l'image ici

Kalaiselvan
la source
0

Dans mon cas pour créer une nouvelle installation de la classe "TableBotDataStore" (framework de bot MS), nous transmettons le paramètre "tableName" avec un trait d'union comme "master-bot" et TableBotDataStore ne peut avoir des noms de table qu'avec des lettres et des chiffres uniquement

igor_bugaenko
la source
0

J'ai eu le même problème, la fonction passait la containerNameKeychaîne as. ci-dessous est le code qui a donné une erreur

container = blobClient.GetContainerReference(containerNameKey) 

Je l'ai changé en

container = blobClient.GetContainerReference(ConfigurationManager.AppSettings(containerNameKey).ToString()) 

Ça a marché

Vani
la source