L'archiviazione tabelle di Azure restituisce 400 richieste non valide


119

L'ho eseguito in modalità debug e allego un'immagine con i dettagli dell'eccezione. Come posso sapere cosa è andato storto? Stavo cercando di inserire i dati in una tabella. Azzurro non può fornirmi maggiori dettagli?

Obs: l'archiviazione è su Windows Azure non sulla mia macchina. Le tabelle sono state create, ma ottengo questo errore durante l'inserimento dei dati

inserisci qui la descrizione dell'immagine

// 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();

ed ecco il codice di inserimento:

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);
    }
}

Quell'immagine non aiuta davvero, a parte la conferma dell'errore 400. Sarebbe "utile" mostrare il codice che hai eseguito che ha provocato la richiesta errata: come hai impostato il client di archiviazione, come hai impostato la tabella, quindi è andato da inserire, ecc.
David Makogon

Ho copiato e incollato il codice. Spero che questo aiuti
Ryan

Sarebbe utile se dicessi quale dei diversi casi sta fallendo. Inoltre, apparentemente stai impostando alcune proprietà al di fuori di questo codice (ad esempio, PartitionKey e RowKey) quindi sarebbe utile sapere quali sono e su cosa sono impostate.
Brian Reischl

Ho notato che quando l'eccezione viene lanciata per prima, non c'è l'opzione "Visualizza dettagli" ma quando continui il debug e il flusso torna al chiamante (dove l'eccezione si apre di nuovo), puoi vedere l'opzione Visualizza dettagli. Da lì puoi usare la risposta di @Juha Palomäki per trovare l'errore
raghav710

Risposte:


148

Errore 400 significa che c'è qualcosa che non va nel valore di una delle tue proprietà. Un modo per scoprirlo è tracciare la richiesta / risposta tramite Fiddler e vedere i dati effettivi inviati a Windows Azure Storage.

Facendo un'ipotesi, presumo dando una rapida occhiata al tuo codice che nel tuo modello tu abbia alcune proprietà di tipo Data / Ora (OfflineTimestamp, OnlineTimestamp) e ho osservato che in alcuni scenari uno di essi è inizializzato con il valore predefinito che è " DateTime.MinValue ". Si noti che il valore minimo consentito per un attributo di tipo Data / ora è Jan 1, 1601 (UTC) in Windows Azure [http://msdn.microsoft.com/en-us/library/windowsazure/dd179338.aspx] . Si prega di vedere se non è così. In tal caso, è possibile renderli campi di tipo nullable in modo che non vengano popolati con i valori predefiniti.

Dai un'occhiata anche alla risposta di Juha Palomäki qui sotto ... a volte c'è un messaggio leggermente più utile nell'eccezione in cui suggerisce (RequestInformation.ExtendedErrorInformation.ErrorMessage)


259
Per l'amor di Dio, se qualcuno del team di Azure legge questo messaggio, fare in modo che l'SDK restituisca più informazioni rispetto all'errore 400 Bad Request. Non ho idea del motivo per cui DateTime nell'archiviazione tabelle non possa avere la stessa data minima dell'oggetto .NET DateTime, ma ho perso una buona giornata su questo. Quando sono arrivato alla proprietà che ha causato il problema, mi sono imbattuto anche in questo, il che ha aiutato. Ora, prima di inserire / aggiornare un modello con DateTime per l'archiviazione delle tabelle, devo eseguire i controlli su tutte le proprietà DateTime. NON è l'ideale ...
Michael

8
Già che ci siamo, non puoi avere anche una proprietà enum. Ho dovuto convertire la proprietà in Integer
Martin

15
Apparentemente, anche i nomi delle tabelle non possono contenere trattini. Mi ci è voluta un'ora per capirlo.
Amogh Natu

4
I nomi delle tabelle non possono nemmeno avere trattini bassi .. ecco perché sono qui
Quango

2
Immagino che RowKey non sia inizializzato con una stringa vuota poiché questo è il valore di ricerca principale e solo la colonna indicizzata ... è per ricordarti di popolarlo avrei pensato ... questa è solo una mia ipotesi però ... Per quanto riguarda i nomi delle tabelle vanno .. leggete questo ... blogs.msdn.microsoft.com/jmstall/2014/06/12/…
dreadeddev

129

StorageException contiene anche informazioni un po 'più dettagliate sull'errore.

Check in debugger: StorageException.RequestInformation.ExtendedInformation

inserisci qui la descrizione dell'immagine


6
Perché queste informazioni non sono un'eccezione di primo livello?
Wilko van der Veen

Per me questo ha evidenziato .. "Aggiungi blob non supportato dall'emulatore" .. FML
Michiel Cornille

The specifed resource name contains invalid characters.il nome del mio tavolo aveva dei trattini ... proprio come i nomi delle mie code ... sigh. Si spera che la ricerca raccolga questo per più persone! vedi: stackoverflow.com/questions/45305556/...
Nateous

55

Nel mio caso è stata una barra in avanti nella RowKey .

Ho anche ricevuto un messaggio "OutOfRangeInput - Uno degli input della richiesta è fuori intervallo". errore durante il tentativo di aggiunta manuale tramite l'emulatore di archiviazione.

Caratteri non consentiti nei campi chiave

I seguenti caratteri non sono consentiti nei valori per le proprietà PartitionKey e RowKey :

  • Il carattere barra ( / )
  • Il carattere barra rovesciata ( \ )
  • Il carattere del segno del numero ( # )
  • Il punto interrogativo ( ? )
  • Caratteri di controllo da U + 0000 a U + 001F , inclusi:
    • Il carattere di tabulazione orizzontale ( \ t )
    • Il carattere di avanzamento riga ( \ n )
    • Il carattere di ritorno a capo ( \ r )
    • Caratteri di controllo da U + 007F a U + 009F

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

Ho scritto un metodo di estensione per gestirlo per me.

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();
}

4
Questo era anche il mio problema. Il tuo metodo di estensione funziona come un campione!
James Wilson

1
Ho adorato il metodo di estensione. Mi ha salvato.
Newton Sheikh

Risposta Alternate qui dato che fa un regex sostituire stackoverflow.com/a/28788382/285795
ΩmegaMan

Risolto il problema per me. Ho avuto un taglio in avanti. Sembrava un buon carattere per una pseudo chiave composta.
richard

Questo metodo di estensione non rimuove diversi caratteri non consentiti. Ad esempio: space, "(", ")" ... docs.microsoft.com/en-us/rest/api/storageservices/…
Tiago Andrade e Silva

6

Ho affrontato lo stesso problema, ma il motivo nel mio caso era dovuto alle dimensioni. Dopo aver esaminato le proprietà aggiuntive dell'eccezione (RequestInformation.ExtendedErrorInformation), ho trovato il motivo:

ErrorCode: PropertyValueTooLarge ErrorMessage: il valore della proprietà supera la dimensione massima consentita (64 KB). Se il valore della proprietà è una stringa, è codificato UTF-16 e il numero massimo di caratteri deve essere 32 KB o inferiore.


5

bene, nel mio caso stavo cercando di fare questo:

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

a causa di ContainerName SessionMaterials(come l'abitudine di scrivere in Pascal Case e Camel Case: D) stava causando 400 richieste errate. Quindi, devo solo farlo sessionmaterials. e ha funzionato.

Spero che questo aiuti qualcuno.

PS: - Basta controllare la risposta http di eccezione o utilizzare fiddler per acquisire la richiesta e la risposta.


3

nel mio caso: il nome del contenitore era in maiuscolo. ci sono limitazioni quando si usano i caratteri. inserisci qui la descrizione dell'immagine


Questo vale anche per i nomi delle proprietà delle tabelle.
Iain Ballard


1

Una documentazione da MS su tutti i codici di errore del servizio al tavolo può essere trovata qui


1

Ho avuto lo stesso errore BadRequest (400), alla fine lo riempio manualmente:

inserisci qui la descrizione dell'immagine

E ha funzionato per me. Spero che questo ti aiuti!


Questa risposta è corretta. Ho sprecato circa un'ora e si è spento che anche Timestampdeve essere generato manualmente. È veramente noioso.
Roman Koliada

0

Ho anche affrontato lo stesso tipo di problema. Nel mio caso il valore PartitionKey non è stato impostato, quindi per impostazione predefinita il valore PartitionKey era null, il che ha comportato Object reference not set to an instance of an object.un'eccezione

Controlla se stai fornendo i valori appropriati per PartitionKey o RowKey, potresti incontrare questo problema.


0

Ho risolto i miei casi e ha funzionato bene

I miei casi:

  1. La chiave di riga non è nel formato corretto (400).
  2. La combinazione di partitionkey e rowkey non è univoca (409).

0

Ricevo 400 Bad Request perché stavo utilizzando ZRS (Zone Redundant Storage) e Analytics non è disponibile per questo tipo di archiviazione. Non sapevo di utilizzare Analytics.

Ho eliminato il contenitore di archiviazione e l'ho ricreato come GRS e ora funziona correttamente.


0

Stavo ricevendo un (400) Bad Request, StatusMessage: Bad Request, ErrorCode: OutOfRangeInput quando l'entità aveva una proprietà DateTime non impostata (= DateTime.MinValue)


0

Nel mio caso: ho incluso i metadati del blob con un nome di tag contenente un trattino.

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

Il trattino "added-by"era il problema e in seguito RTFM mi ha detto che i nomi dei tag devono essere conformi alle convenzioni degli identificatori C #.

Rif: https://docs.microsoft.com/en-us/azure/storage/blobs/storage-properties-metadata

Il carattere di sottolineatura funziona bene.


0

Nel mio caso, non dovrei aggiungere PartitionKey e Rowkey nella mia classe di entità. Dovrebbe essere della classe base. Di seguito funzionerebbe.

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


      public TableRunLogMessage() { }
}

0

Se stai usando NodeJS e ti sei imbattuto in questo post, solo per scoprire che non ottieni quelle belle informazioni dettagliate nel tuo oggetto errore; puoi utilizzare un proxy per ottenere quei dettagli. Tuttavia, poiché nessuno qui menziona COME usare un proxy.

Il modo più semplice con NodeJS è impostare due variabili ambientali:

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.

Se stai effettivamente utilizzando C #, come sta facendo l'autore di questo post; puoi semplicemente installare Fiddler e impostarlo per l'intercettazione. Per impostazione predefinita, dovrebbe intercettare le richieste. Potrebbe essere necessario considerare attendibile anche il certificato di Fiddler o altrimenti eseguire l'equivalente di "NODE_TLS_REJECT_UNAUTHORIZED = 0" di Node.


0

Ho ricevuto una risposta 400-BadRequest dall'API della tabella dell'account di archiviazione di Azure. Le informazioni sull'eccezione hanno mostrato che "L'account a cui si accede non supporta http.". Ho pensato che dobbiamo usare https nella stringa di connessione quando "Trasferimento sicuro richiesto" è abilitato nella configurazione dell'account di archiviazione come mostrato nell'immagine sottostante.inserisci qui la descrizione dell'immagine


0

Nel mio caso per creare una nuova installazione della classe "TableBotDataStore" (framework MS bot) passiamo il parametro "tableName" con trattino come "master-bot" e TableBotDataStore può avere nomi di tabella solo con lettere e numeri


0

Ho avuto lo stesso problema, la funzione stava passando la containerNameKeystringa as. di seguito è riportato il codice che ha dato l'errore

container = blobClient.GetContainerReference(containerNameKey) 

L'ho cambiato in

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

Ha funzionato

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.