简体   繁体   中英

Azure table storage returns 400 Bad Request

I ran this in debug mode, and I attach an image with the details of the exception. How can I know what went wrong? I was trying to inset data in a table. Can't azure give me more details?

Obs: The storage is on Windows Azure not on my machine. The tables were created, but I get this error when inserting data

在此处输入图片说明

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

and here is the insert code:

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

400 Error means there's something wrong with the value of one of your properties. One way to find out is to trace the request/response through Fiddler and see the actual data being sent to Windows Azure Storage.

Taking a wild guess, I'm assuming by taking a quick glance at your code that in your model you have some Date/Time type properties (OfflineTimestamp, OnlineTimestamp) and observed that in certain scenarios one of them is initialized with the default value which is " DateTime.MinValue ". Please note that the minimum value allowed for a Date/Time type attribute is Jan 1, 1601 (UTC) in Windows Azure [http://msdn.microsoft.com/en-us/library/windowsazure/dd179338.aspx] . Please see if that's not the case. If that's the case, then you could make them nullable type fields so that they don't get populated with the default values.

Have a look at Juha Palomäki's answer below as well... there sometimes is a slightly more useful message in the exception where he suggests (RequestInformation.ExtendedErrorInformation.ErrorMessage)

The StorageException contains also a little bit more detailed information about error.

Check in debugger: StorageException.RequestInformation.ExtendedInformation

在此处输入图片说明

In my case it was a forward slash in the RowKey .

I also received an 'OutOfRangeInput - One of the request inputs is out of range.' error when trying to add manually through the storage emulator.

Characters Disallowed in Key Fields

The following characters are not allowed in values for the PartitionKey and RowKey properties:

  • The forward slash ( / ) character
  • The backslash ( \\ ) character
  • The number sign ( # ) character
  • The question mark ( ? ) character
  • Control characters from U+0000 to U+001F , including:
    • The horizontal tab ( \\t ) character
    • The linefeed ( \\n ) character
    • The carriage return ( \\r ) character
    • Control characters from U+007F to U+009F

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

I wrote an extension method to handle this for 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();
}

I faced the same issue but the reason in my case was due to size. After digging into the additional exception properties (RequestInformation.ExtendedErrorInformation), found the reason:

ErrorCode : PropertyValueTooLarge ErrorMessage: The property value exceeds the maximum allowed size (64KB). If the property value is a string, it is UTF-16 encoded and the maximum number of characters should be 32K or less.

well, in my case i was trying to do this:

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

because of ContainerName SessionMaterials (as a habit writing in Pascal Case and Camel Case :D) it was causing 400 bad request. So, I just have to make it sessionmaterials . and it worked.

Hope this helps some one.

PS:- Just check exception http response or use fiddler to capture request and response.

Sometimes it's because your partitionKey or rowKey is NULL

(it was the case for me)

in my case : Container name was in capital letter. there are limitations when using chars. 在此处输入图片说明

可以在此处找到 MS 有关所有表服务错误代码的文档

I had the same BadRequest(400) Error, at the end I fill manually :

在此处输入图片说明

And worked for me. Hope this helps!

I also faced same kind of issue. In my case PartitionKey value was not set, so by default PartitionKey value was null, which resulted in Object reference not set to an instance of an object. exception

Check if you are providing the appropriate values for PartitionKey or RowKey, you may face such problem.

I fixed my cases and it worked fine

My cases:

  1. Row key is not in correct format (400).
  2. Combination of partitionkey and rowkey is not unique (409).

I was getting a 400 Bad Request because I was using ZRS (Zone Redundant Storage), and Analytics isn't available for this type of storage. I wasn't aware I was using Analytics.

I deleted the storage container and recreated as GRS and now it works fine.

当实体的属性 DateTime 未设置 (= DateTime.MinValue) 时,我收到了 (400) Bad Request, StatusMessage:Bad Request, ErrorCode:OutOfRangeInput

In my case: I included blob metadata with a tag name containing a hyphen.

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

The dash in "added-by" was the problem, and later RTFM told me that tag names must conform to C# identifier conventions.

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

Underscore works fine.

In my case, i should not add PartitionKey and Rowkey in my entity class. It should be from the base class. Below would just work.

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


      public TableRunLogMessage() { }
}

If you're using NodeJS and stumbled across this post, only to find that you don't get that lovely detailed information in your error object; you can utilize a proxy to get those details. However, since no one here mentions HOW to use a proxy.

The simplest way with NodeJS is by setting two environmental variables:

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.

If you're actually utilizing C#, like the author of this post is doing; you can simply install Fiddler and set it to intercept. By default it should intercept the requests. You may need to also trust Fiddler's certificate or otherwise do the equivalent of Node's "NODE_TLS_REJECT_UNAUTHORIZED=0".

I got 400-BadRequest response from Azure Storage Account Table API. Exception information showed that "The account being accessed does not support http.". I figured that we must use https in the connection string when "Secure transfer required" is enabled in storage account configuration as shown in the below image. 在此处输入图片说明

在我创建“TableBotDataStore”类(MS bot框架)的新实例的情况下,我们传递带有连字符的“tableName”参数,如“master-bot”,而TableBotDataStore的表名只能包含字母和数字

I had the same issue, the function was passing the containerNameKey as string. below is the code that gave error

container = blobClient.GetContainerReference(containerNameKey) 

I changed it to

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

It worked

I got 400-BadRequest response when I tried to put too long value to the string field.

"A UTF-16-encoded value. String values may be up to 64 KiB in size. Note that the maximum number of characters supported is about 32 K or less."

https://docs.microsoft.com/en-us/rest/api/storageservices/understanding-the-table-service-data-model

对我来说,我使用带破折号的表名示例:tablename: "table-1234",但没有破折号的 tablename: "table1234" 工作。

For me, I tried to insert an entity into an Azure Storage Table with a PartitionKey/RowKey that included the "#" character. Annoying that this is disallowed, since it is common to use "#" as a separator in single-table design.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM