【问题标题】:Azure Storage exception when a string length is more than 32768 characters字符串长度超过 32768 个字符时的 Azure 存储异常
【发布时间】:2017-08-12 23:15:20
【问题描述】:

我的应用程序是 ASP.NET Core 1.0 Web API。如果我的控制器返回一个小字符串,则一切正常。但如果字符串长度超过 32768,我会收到以下错误消息:

--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Server.Kestrel.Internal.Htpp.Frame`1.<RequestProcessAsync>d__2.MoveNext()
Request Information
RequestID:440ed7db-0002-006f-742e-a28f82000000
RequestDate:Tue, 21 Mar 2017 11:30:40 GMT
StatusMessage:Bad Request
ErrorCode:PropertyValueTooLarge

这是我的控制器:

[HttpGet]
[Produces("plain/text")]
public async Task<IActionResult> GetData()
{
    return this.Ok(this.GetResponse());
}

private string GetResponse()
{
    string retVal = string.Empty;
    for (int i = 0; i < 32769; i++)
    {
        retVal = retVal + "a";
    }
    return retVal;
}

完整的错误信息:

Microsoft.WindowsAzure.Storage.StorageException: BadRequest
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.<ExecuteAsyncInternal>d__4`1.MoveNext() in C:\Program Files (x86)\Jenkins\workspace\release_dotnet_master\Lib\Windows Runtime\Core\Executor\Executor.cs:line 315
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter`1.GetResult()
   at MyProjectNameLogging.AzureStorageLoggingConnector.<WriteToRequestLogAsync>d__4.MoveNext() in AzureStorageLoggingTable.cs:line 29
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.GetResult()
   at MyProjectNameLogging.Repositories.RequestLoggingRepository.<WriteToLogAsync>d__6.MoveNext() in Repositories\RequestLoggingRepository.cs:line 36
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.GetResult()
   at MyProjectNameLogging.Middleware.RequestMiddleware.<Invoke>d__2.MoveNext() in Middleware\RequestMiddleware.cs:line 69
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Swashbuckle.SwaggerUi.Application.SwaggerUiMiddleware.<Invoke>d__5.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Swashbuckle.SwaggerUi.Application.RedirectMiddleware.<Invoke>d__4.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Swashbuckle.Swagger.Application.SwaggerMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.<Invoke>d__7.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.<Invoke>d__8.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Server.Hosting.Internal.RequestServiceContainerMiddleware.<Invoke>d__3.MoveNext()
--- End of stack trace previous location where exception was thrown ---
   at System.Runtime.CompillerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompillerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Server.Kestrel.Internal.Htpp.Frame`1.<RequestProcessAsync>d__2.MoveNext()
Request Information
RequestID:6d8afaf4-0002-00cd-1235-a2421e000000
RequestDate:Tue, 21 Mar 2017 12:24:57 GMT
StatusMessage:Bad Request
ErrorCode:PropertyValueTooLarge

我想返回比 32768 更长的字符串。

有什么建议吗?

【问题讨论】:

  • 虽然它对您没有帮助,但如果该错误消息是文本而不是图像,其他人可能会受益,因为它会在他们搜索相同问题时出现。甚至可能会为您和任何回答的人带来一些支持!
  • 什么是Ok()
  • @JuryGolubev 它是来自抽象类 ControllerBase 的方法
  • @MoritzSchmidt 仅供参考,我只是按原样运行相同的代码,并将其从"a" 更改为"aa",并且两次都有效。我在 Docker 中运行;我不确定这是否会有所不同。
  • 看起来你正在绊倒与 Azure 相关的东西,因此可能值得专门标记它。该错误 (PropertyValueTooLarge) 带来了许多与 Azure 相关的内容,并且您的文件名也提到了 Azure。

标签: c# asp.net azure asp.net-core azure-table-storage


【解决方案1】:

您遇到了字符串属性类型 (source) 的 Azure 存储限制:

Edm.String (String) - 一个 UTF-16 编码的值。字符串值最大可达 64 KB。

因为 UTF-16 编码的字符串需要 2 个字节来存储一个字符,所以最大字符串长度为 32768 个字符。

【讨论】:

  • 原来我试图记录哪个即时响应 azure ,由于 64KB 的限制,这是不可能的。再次感谢您为我节省了很多时间..
  • 记录数据使用 BLOB 存储。 Azure Storage Services (Blob Service)
  • 原来我试图记录我正在响应的数据,由于 64KB 的限制,这是不可能的。再次感谢您为我节省了很多时间..
  • 这种情况有时会发生有什么原因吗?我用相同的数据(字符串大小约为 200Kb)尝试了几次,有时它会抛出异常,有时它有效.. 有什么想法吗?
  • @Moritz,我不知道。向 Azure 支持人员提出该问题。他们应该知道他们的代码是如何工作的。
【解决方案2】:

虽然已经回答了这个问题,但我想为可能遇到此线程的其他人提出解决方案。我需要在我的表实体的单个属性中存储超过 64k 的数据。我在网上找到了几个 Lokad Fat Entities 的参考资料,但是,它似乎不再受到积极支持,而且我在 NuGet.org 上提供的版本出现运行时错误。因此,这是一个受 Lokad 解决方案启发的课程。我希望其他人觉得它有用。

    public class ExtEntity<T> : TableEntity where T : new()
{
    private const int MAX_BYTES_PER_ARR = 65500; // don't use full 64k to avoid any weird edge case

    // Serialized in DB and deserialized for callers
    public Byte[] A0 { get; set; }
    public Byte[] A1 { get; set; }
    public Byte[] A2 { get; set; }
    public Byte[] A3 { get; set; }
    public Byte[] A4 { get; set; }
    public Byte[] A5 { get; set; }
    public Byte[] A6 { get; set; }
    public Byte[] A7 { get; set; }
    public Byte[] A8 { get; set; }
    public Byte[] A9 { get; set; }
    public Byte[] A10 { get; set; }
    public Byte[] A11 { get; set; }
    public Byte[] A12 { get; set; }
    public Byte[] A13 { get; set; }
    public Byte[] A14 { get; set; }
    public Byte[] A15 { get; set; }
    private T value;

    public T Value
    {
        // Accessors automatically serialize and deserialize T value
        get
        {
            // ASSUMES that value will never change after first time deserialized!
            if (this.value == null)
            {
                int n = 0;
                using (var memStream = new MemoryStream())
                {
                    while (true)
                    {
                        string propName = "A" + n++;
                        PropertyInfo prop = this.GetType().GetProperty(propName);
                        byte[] arr = (byte[])prop.GetValue(this);
                        if (arr == null || arr.Length == 0)
                        {
                            break;
                        }
                        memStream.Write(arr, 0, arr.Length);
                    }
                    memStream.Seek(0, SeekOrigin.Begin);
                    var binForm = new BinaryFormatter();
                    this.value = (T)binForm.Deserialize(memStream);
                }
            }
            return this.value;
        }
        set
        {
            // First, ensure the type is serializable.
            if (!typeof(T).IsSerializable && !(typeof(ISerializable).IsAssignableFrom(typeof(T))))
                throw new InvalidOperationException("ExtEntity<T>.get_Value Exception: A serializable Type is required.");

            // Assign the value
            this.value = value;

            // Then searialize it for Table Storage use
            BinaryFormatter bf = new BinaryFormatter();
            using (var memStream = new MemoryStream())
            {
                // Serialize into memory stream, then seek back to origin
                bf.Serialize(memStream, this.value);
                memStream.Seek(0, SeekOrigin.Begin);

                // Chunk data from memory stream into stored properties
                int bytesRemaining = (int)memStream.Length;
                int n = 0;
                while (bytesRemaining > 0)
                {
                    if (n > 15)
                    {
                        throw new ApplicationException("ExtEntity<T>.set_Value Exception: Data is too large.");
                    }
                    int numToRead = Math.Min(bytesRemaining, ExtEntity<T>.MAX_BYTES_PER_ARR);
                    byte[] arr = new byte[numToRead];
                    int numRead = memStream.Read(arr, 0, numToRead);
                    if (numRead != numToRead)
                    {
                        throw new ApplicationException("ExtEntity<T>.set_Value Exception: Unexpected number of bytes returned.");
                    }

                    string propName = "A" + n++;
                    PropertyInfo prop = this.GetType().GetProperty(propName);
                    prop.SetValue(this, arr);
                    bytesRemaining -= numRead;
                }
            }
        }
    }
}

示例用法:

public class RawDataBlockEntity : ExtEntity<RawDataBlock>
{
    public RawDataBlockEntity(string rawDataId, string blockId, RawDataBlock block)
    {
        this.PartitionKey = rawDataId;
        this.RowKey = blockId;

        this.Value = block;
    }

    public RawDataBlockEntity() { }
}

【讨论】:

    【解决方案3】:

    试试这个:

    return new ContentResult { Content = this.GetResponse(), StatusCode = 200 };
    

    【讨论】:

    • 有什么解释吗?
    猜你喜欢
    • 1970-01-01
    • 2012-09-08
    • 1970-01-01
    • 2020-03-19
    • 2021-06-20
    • 1970-01-01
    • 2011-05-03
    • 1970-01-01
    • 2013-09-27
    相关资源
    最近更新 更多