Magazyn tabel Azure zwraca 400 złych żądań

119

Uruchomiłem to w trybie debugowania i dołączam obraz ze szczegółami wyjątku. Skąd mogę wiedzieć, co poszło nie tak? Próbowałem wstawić dane do tabeli. Czy lazur nie może podać mi więcej szczegółów?

Obs: Magazyn znajduje się w systemie Windows Azure, a nie na moim komputerze. Tabele zostały utworzone, ale podczas wstawiania danych pojawia się ten błąd

wprowadź opis obrazu tutaj

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

a oto kod wstawiania:

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
źródło
To zdjęcie tak naprawdę nie pomaga, poza potwierdzeniem błędu 400. Czy "pomogłoby" byłoby pokazanie kodu, który wykonałeś, co spowodowało złe żądanie: jak skonfigurowałeś klienta magazynu, jak skonfigurowałeś tabelę, a następnie poszedł wstawić itp.
David Makogon
Skopiowałem i wkleiłem kod. Mam nadzieję, że to pomoże
Ryan
Pomogłoby, gdybyś powiedział, który z kilku przypadków zawodzi. Poza tym najwyraźniej ustawiasz niektóre właściwości poza tym kodem (np. PartitionKey i RowKey), więc warto wiedzieć, jakie to są i do czego są ustawiane.
Brian Reischl,
Zauważyłem, że gdy wyjątek jest rzucany jako pierwszy, nie ma opcji „Wyświetl szczegóły”, ale gdy kontynuujesz debugowanie i przepływ wraca do wywołującego (gdzie wyjątek pojawia się ponownie), możesz zobaczyć opcję Wyświetl szczegóły. Stamtąd możesz użyć odpowiedzi @Juha Palomäki, aby znaleźć błąd
raghav710

Odpowiedzi:

148

Błąd 400 oznacza, że ​​coś jest nie tak z wartością jednej z twoich właściwości. Jednym ze sposobów, aby się tego dowiedzieć, jest prześledzenie żądania / odpowiedzi za pomocą programu Fiddler i sprawdzenie rzeczywistych danych wysyłanych do magazynu Windows Azure.

Przyjmując dzikie przypuszczenie, zakładam, rzucając okiem na twój kod, że w modelu masz pewne właściwości typu Data / Czas (OfflineTimestamp, OnlineTimestamp) i zauważyłem, że w niektórych scenariuszach jeden z nich jest inicjowany z wartością domyślną, która to „ DateTime.MinValue ”. Należy pamiętać, że minimalna dozwolona wartość atrybutu typu Data / godzina to 1 stycznia 1601 (UTC) w systemie Windows Azure [http://msdn.microsoft.com/en-us/library/windowsazure/dd179338.aspx] . Sprawdź, czy tak nie jest. W takim przypadku możesz uczynić je polami typu nullable, aby nie były wypełniane wartościami domyślnymi.

Spójrz na odpowiedź Juha Palomäkiego również poniżej ... czasami jest nieco bardziej przydatna wiadomość w wyjątku, w którym sugeruje (RequestInformation.ExtendedErrorInformation.ErrorMessage)

Przerwano współtworzenie
źródło
259
Na miłość boską, jeśli ktoś z zespołu platformy Azure to przeczyta, spraw, aby zestaw SDK zwrócił więcej informacji niż błąd 400 Złe żądanie. Nie mam pojęcia, dlaczego DateTime w magazynie tabeli nie może mieć tej samej minimalnej daty co obiekt .NET DateTime, ale zmarnowałem dobry dzień na ten. Zanim doszedłem do tego, która nieruchomość spowodowała problem, również się z tym spotkałem, co pomogło. Teraz, zanim kiedykolwiek wstawię / zaktualizuję model za pomocą DateTime do przechowywania tabeli, muszę sprawdzić wszystkie właściwości DateTime. NIE idealne ...
Michael,
8
Skoro już o tym mowa, nie możesz mieć również właściwości enum. Musiałem zamienić nieruchomość na Integer
Martin
15
Najwyraźniej nazwy tabel również nie mogą zawierać łączników. Zajęło mi godzinę, zanim to rozgryzłem.
Amogh Natu
4
Nazwy tabel też nie mogą mieć podkreślenia ... dlatego tu jestem
Quango
2
Wyobrażam sobie, że RowKey nie jest zainicjowany pustym ciągiem, ponieważ jest to główna wartość wyszukiwania i tylko zindeksowana kolumna ... ma przypominać o wypełnieniu jej, tak bym pomyślał ... to tylko moje przypuszczenie ... O ile nazwy tabel idą .. przeczytaj to ... blogs.msdn.microsoft.com/jmstall/2014/06/12/…
dreadeddev
129

StorageException zawiera również nieco bardziej szczegółowe informacje o błędzie.

Sprawdź debuger: StorageException.RequestInformation.ExtendedInformation

wprowadź opis obrazu tutaj

Juha Palomäki
źródło
6
Dlaczego ta informacja nie jest wyjątkiem na najwyższym poziomie?
Wilko van der Veen
Dla mnie to wyróżnione .. "Dołącz blob nieobsługiwany przez emulator" .. FML
Michiel Cornille
The specifed resource name contains invalid characters.nazwa mojego stołu miała w sobie myślniki ... tak jak nazwy moich kolejek ... westchnij. Miejmy nadzieję, że wyszukiwanie znajdzie to dla większej liczby osób! zobacz: stackoverflow.com/questions/45305556/…
Nateous
55

W moim przypadku był to ukośnik RowKey .

Otrzymałem również komunikat „OutOfRangeInput - Jedno z danych wejściowych żądania jest poza zakresem”. błąd podczas próby ręcznego dodania za pomocą emulatora magazynu.

Postacie niedozwolone w kluczowych polach

Następujące znaki nie są dozwolone w wartościach właściwości PartitionKey i RowKey :

  • Znak ukośnika ( / )
  • Znak ukośnika odwrotnego ( \ )
  • Znak liczby ( # )
  • Znak zapytania ( ? )
  • Znaki sterujące od U + 0000 do U + 001F , w tym:
    • Znak tabulacji poziomej ( \ t )
    • Znak wysuwu wiersza ( \ n )
    • Znak powrotu karetki ( \ r )
    • Znaki sterujące od U + 007F do U + 009F

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

Napisałem metodę rozszerzenia, aby sobie z tym poradzić.

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
źródło
4
To też był mój problem. Twoja metoda rozszerzenia działa jak mistrz!
James Wilson,
1
Uwielbiałem metodę przedłużania. Uratował mnie.
Newton Sheikh
Podano tutaj alternatywną odpowiedź, która zastępuje wyrażenie regularne stackoverflow.com/a/28788382/285795
ΩmegaMan
Naprawiłem to dla mnie. Cięcie do przodu. Wydawało się, że to dobry znak dla pseudozłożonego klucza.
richard
Ta metoda rozszerzenia nie usuwa kilku niedozwolonych znaków. Np .: spacja, „(”, „)” ... docs.microsoft.com/en-us/rest/api/storageservices/
Tiago Andrade e Silva
6

Napotkałem ten sam problem, ale przyczyną w moim przypadku był rozmiar. Po zagłębieniu się w dodatkowe właściwości wyjątku (RequestInformation.ExtendedErrorInformation) znalazłem przyczynę:

ErrorCode: PropertyValueTooLarge ErrorMessage: Wartość właściwości przekracza maksymalny dozwolony rozmiar (64 KB). Jeśli wartość właściwości jest ciągiem, jest zakodowana w formacie UTF-16, a maksymalna liczba znaków nie może przekraczać 32 KB.

Nibras Manna
źródło
5

cóż, w moim przypadku próbowałem to zrobić:

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

z powodu ContainerName SessionMaterials(co jest nawykiem pisania w Pascal Case i Camel Case: D) powodowało to 400 złych żądań. Więc po prostu muszę to zrobić sessionmaterials. i zadziałało.

Mam nadzieję, że to komuś pomoże.

PS: - Po prostu sprawdź odpowiedź http wyjątku lub użyj fiddlera do przechwycenia żądania i odpowiedzi.

Jawand Singh
źródło
3

w moim przypadku: nazwa kontenera była zapisana wielką literą. istnieją ograniczenia podczas używania znaków. wprowadź opis obrazu tutaj

Ravi Anand
źródło
Dotyczy to również nazw właściwości tabel.
Iain Ballard
3

Czasami to dlatego, że jesteś partitionKeylub rowKeyjestNULL

(tak było w moim przypadku)

Maroine Abdellah
źródło
1

Dokumentację firmy MS dotyczącą wszystkich kodów błędów obsługi tabel można znaleźć tutaj

huha
źródło
1

Miałem ten sam błąd BadRequest (400), na koniec wypełniam ręcznie:

wprowadź opis obrazu tutaj

I pracował dla mnie. Mam nadzieję że to pomoże!

Gatsby
źródło
Ta odpowiedź jest poprawna. Zmarnowałem około godziny i okazało się, że nawet Timestamptrzeba to wygenerować ręcznie. To jest naprawdę denerwujące.
Roman Koliada
0

Miałem też podobny problem. W moim przypadku wartość PartitionKey nie została ustawiona, więc domyślnie PartitionKey ma wartość null, co spowodowało Object reference not set to an instance of an object.wyjątek

Sprawdź, czy podajesz odpowiednie wartości dla PartitionKey lub RowKey, możesz napotkać taki problem.

Dilip Nannaware
źródło
0

Naprawiłem moje przypadki i działało dobrze

Moje sprawy:

  1. Klucz wiersza ma nieprawidłowy format (400).
  2. Połączenie klucza partycji i klucza wiersza nie jest unikalne (409).
Kurkula
źródło
0

Otrzymałem 400 złych żądań, ponieważ korzystałem z ZRS (Zone Redundant Storage), a Analytics nie jest dostępny dla tego typu magazynu. Nie wiedziałem, że korzystam z Analytics.

Usunąłem kontener do przechowywania i odtworzyłem jako GRS, a teraz działa dobrze.

Aidan
źródło
0

Otrzymałem (400) Bad Request, StatusMessage: Bad Request, ErrorCode: OutOfRangeInput, gdy jednostka miała ustawioną właściwość DateTime (= DateTime.MinValue)

Stig
źródło
0

W moim przypadku: dołączyłem metadane obiektu BLOB z nazwą tagu zawierającą łącznik.

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

"added-by"Problemem była myślnik , a później RTFM powiedział mi, że nazwy tagów muszą być zgodne z konwencjami identyfikatorów C #.

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

Podkreślenie działa dobrze.

Steve Friedl
źródło
0

W moim przypadku nie powinienem dodawać PartitionKey i Rowkey do mojej klasy encji. Powinien pochodzić z klasy bazowej. Poniżej po prostu zadziała.

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


      public TableRunLogMessage() { }
}
wesoły
źródło
0

Jeśli używasz NodeJS i natknąłeś się na ten post, tylko po to, aby odkryć, że nie masz tak pięknych szczegółowych informacji w swoim obiekcie błędu; możesz użyć proxy, aby uzyskać te szczegóły. Ponieważ jednak nikt tutaj nie wspomina JAK używać proxy.

Najprostszym sposobem korzystania z NodeJS jest ustawienie dwóch zmiennych środowiskowych:

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.

Jeśli faktycznie używasz C #, tak jak robi to autor tego postu; możesz po prostu zainstalować Fiddlera i ustawić go na przechwytywanie. Domyślnie powinien przechwytywać żądania. Może być konieczne zaufanie do certyfikatu Fiddlera lub w inny sposób wykonanie odpowiednika „NODE_TLS_REJECT_UNAUTHORIZED = 0” węzła.

Doug
źródło
0

Otrzymałem odpowiedź 400-BadRequest z interfejsu API tabeli kont magazynu Azure. Informacje o wyjątku wskazują, że „Konto, do którego uzyskiwany jest dostęp, nie obsługuje protokołu http.”. Pomyślałem, że musimy używać protokołu HTTPS w parametrach połączenia, gdy w konfiguracji konta magazynu jest włączona opcja „Wymagany bezpieczny transfer”, jak pokazano na poniższym obrazku.wprowadź opis obrazu tutaj

Kalaiselvan
źródło
0

W moim przypadku do stworzenia nowej instalacji klasy "TableBotDataStore" (framework bota MS) przekazujemy parametr "tableName" z myślnikiem typu "master-bot" a TableBotDataStore może mieć nazwy tabel zawierające tylko litery i cyfry

igor_bugaenko
źródło
0

Miałem ten sam problem, funkcja przekazywała containerNameKeyciąg as. poniżej znajduje się kod, który spowodował błąd

container = blobClient.GetContainerReference(containerNameKey) 

Zmieniłem to na

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

Zadziałało

Vani
źródło