【问题标题】:Uploading async to Azure Blob Storage never returns将异步上传到 Azure Blob 存储永远不会返回
【发布时间】:2016-10-10 05:04:32
【问题描述】:

我正在尝试使用异步方法将文件上传到 Azure Blob 存储,然后设置其元数据,但 UploadFromByteArrayAsync 方法永远不会返回。

我有以下代码:

var connAzureBlob = ConfigurationManager.AppSettings["AzureBlobStorage"];    
var storageAccount = CloudStorageAccount.Parse(connAzureBlob);
var blobClient = storageAccount.CreateCloudBlobClient();

var fileContainer = blobClient.GetContainerReference(ConfigurationManager.AppSettings["AzureBlobContainer"]);
if (!fileContainer.Exists())
{
    await fileContainer.CreateAsync();
    await fileContainer.SetPermissionsAsync(new BlobContainerPermissions {
                                                                             PublicAccess = BlobContainerPublicAccessType.Blob
                                                                         });
}

try
{
    var fileBlob = fileContainer.GetBlockBlobReference(documentId.ToString());
    await fileBlob.UploadFromByteArrayAsync(buffer, 0, buffer.Length);
    Log.Info($"{nameof(SaveToBlobAsync)}: blob {documentId} uploaded.");

    await fileBlob.FetchAttributesAsync();
    fileBlob.Properties.ContentType = contentType;
    fileBlob.Metadata["..."] = "...";
    await fileBlob.SetMetadataAsync();
    Log.Info($"{nameof(SaveToBlobAsync)}: {documentId} - metadata saved.");
}
catch (Exception exception)
{
    Log.Error($"{nameof(SaveToBlobAsync)}: An exception was thrown while saving a file to a blob: ", exception);
    throw;
}

使用上面的代码,我希望看到以下消息:

SaveToBlobAsync:已上传 blob 123。
SaveToBlobAsync: 123 - 元数据已保存。

但这些永远不会出现。

但是,该 blob 似乎已被存储(我可以使用 Azure Storage Explorer 查看其内容),但该进程似乎没有移动到下一行(这将是第一条日志记录消息)。

如果我将所有异步调用切换为它们的非异步对应项,那么代码将按预期工作。

谁能解释为什么UploadFromByteArrayAsync 似乎没有返回?

更新: 我想我会添加更多关于上下文的信息,以防万一。

此代码是从 Web API 方法调用的。有问题的控制器没有异步代码,除了调用存储库方法之外几乎没有其他操作。在调用与 blob 存储接口的类之前,存储库方法会更新 SQL 数据库(同样,所有这些都是非异步代码)。

这个面向 Blob 存储的类具有非异步方法,除了使用 .Wait().Result 调用它们的异步等效项之外,它们几乎没有其他作用。

在有问题的情况下,第二阶段的存储库正在调用非异步版本,因此上述代码本质上是使用.Wait() 调用的。

在上面的代码之前,这个 HTTP 请求从它进入 Web API 的控制器的那一点开始没有其他异步调用。

【问题讨论】:

    标签: c# azure async-await azure-blob-storage


    【解决方案1】:

    该错误几乎肯定在您的调用堆栈中更进一步,其中某些方法阻塞了返回的任务(例如,Task<T>.ResultTask.Wait 等)。如果任务完成需要被阻塞的线程,这将死锁。

    I explain this situation in full on my blog,但它的要点是这样的:

    • await 默认会捕获一个“上下文”并使用它来恢复 async 方法。
    • 如果此代码在 ASP.NET 请求上下文中执行,则此“上下文”为 ASP.NET SynchronizationContext;如果此代码在 UI 线程中执行,则此“上下文”是 UI SynchronizationContext
    • ASP.NET SynchronizationContext 和 UI SynchronizationContext 一次只允许一个线程。

    因此,当调用代码在返回的Task阻塞时,它在该上下文中持有一个线程,从而阻止Task 完成。 p>

    【讨论】:

    • 感谢您的帮助,Stephen,尽管我不确定这种阻塞可能发生在哪里。我已经向 OP 添加了更多信息,以防情况更清楚。
    • @awj:您说“在有问题的情况下,第二阶段的存储库正在调用非异步版本,因此上述代码本质上是使用 .Wait() 调用的。” - 这就是阻塞发生的地方。
    • 你能解释一下为什么我不能用.Wait()调用我的异步方法吗?我在其他地方用过没问题,为什么这里会出问题?
    • @awj:查看我链接到的博客文章;它解释了Wait 如何导致死锁。
    • 如果您需要临时解决方法,请尝试在单独的线程中调用 UploadFromByteArrayAsync,或将其包装在 Task.Run() 中,类似的。只要您在调用 UploadFromByteArrayAsync() 时不在 ASP.NET/UI SyncronizationContext 中,它就不应该死锁。这个 SO 问题解释了更多:stackoverflow.com/questions/19548389/…
    猜你喜欢
    • 2017-07-13
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2019-05-26
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多