Azure 存储表:等待 table.ExecuteAsync(InsertOperation) 执行,但从未完成

Azure Storage Tables: await table.ExecuteAsync(InsertOperation) executes, but never finishes

嗯,我的问题是在 Azure 存储 Table 上调用 await table.ExecuteAsync(...) 确实插入了请求的数据,但从未完成(不 return Table 结果)。 InsertOrUpdate 和 Update 操作的情况相同。我还尝试了具有不同数量属性的不同表 - 同样的问题。

当我调用 table.Execute(...) - 每种操作都运行良好。

这是我的代码 - 就这么简单:

外部调用(在异步操作中放在 MVC Controller 中):

List<Task<ServiceResult<Boolean?>>> addPostTasks = new List<Task<Common.ServiceResult<bool?>>>();              
foreach (var userStream in userStreams)
{
    Task<ServiceResult<Boolean?>> addPostTask = postsStorageSvc.AddImagePost(...);
    postsAddImagePostTasks.Add(addPostTask);
}
Task.WaitAll(addPostTasks.ToArray());

调用的方法:

public async Task<ServiceResult<Boolean?>> AddImagePost(...)
{
ServiceResult<Boolean?> result = new ServiceResult<bool?>(null);
try
{
    PostTableEntity newPost = new PostTableEntity(streamId.ToString(), Guid.NewGuid().ToString(), creatorId, date, htmlText);              
    TableOperation insertOperation = TableOperation.Insert(newPost);
    //Following line never ends!
    TableResult tableResult = await this._storageTableBootstrapper.Table.ExecuteAsync(insertOperation);                
    //Following line works perfect - but is not ASYNC
    TableResult tableResult = this._storageTableBootstrapper.Table.Execute(insertOperation);
}
catch (Exception ex)
{
    result.Result = false;
    result.Errors.Add("AzurePostsStorageService Unexpected error: " + ex.Message);
}
return result;
}

这是一个经典的deadlock由这行造成的:

Task.WaitAll(addPostTasks.ToArray());

尝试将其更改为:

await Task.WhenAll(addPostTasks.ToArray());

基本上 Task.WaitAll 阻塞了请求线程,它无法执行由 await table.ExecuteAsync(...) 发起的 Tasks 的继续。另一种选择是在内部任务中使用 ConfigureAwait(false) 以避免切换 SynchronizatonContext.

await table.ExecuteAsync(...).ConfigureAwait(false);

您可以在不需要切换到原始 SynchronizationContext 时使用 ConfigureAwait(false)。在你的情况下,我相信你可以在服务器上使用所有等待来做到这一点,await 之后的代码是否在线程池上执行并不重要。

有关详细信息,请参阅本文:msdn.microsoft.com/enus/magazine/jj991977.aspx

问题出在这里:

Task.WaitAll(addPostTasks.ToArray());

您的异步方法尝试将自身编组回 ASP.NET 同步上下文,由于您使用 Task.WaitAll.

启动了阻塞调用,该同步上下文被卡住了

相反,您需要一直遵循 async 模式并使用 Task.WhenAll,然后 await

await Task.WhenAll(addPostTasks.ToArray);

Stephan Cleary 在他的博客 post(@NedStoyanov 添加)中详细阐述了这一点:

One other important point: an ASP.NET request context is not tied to a specific thread (like the UI context is), but it does only allow one thread in at a time. This interesting aspect is not officially documented anywhere AFAIK, but it is mentioned in my MSDN article about SynchronizationContext.

如果您为某个组织工作,问题可能出在您的组织启用的代理设置上。我遇到了类似的问题,为了解决这个问题,我使用了以下步骤:

1:在startup.cs

配置中添加如下代码
app.UseDeveloperExceptionPage();
                var webProxy = new WebProxy(new Uri(Configuration["defaultProxy:proxyaddress"]), BypassOnLocal: false);
                var proxyHttpClientHandler = new HttpClientHandler
                {
                    Proxy = webProxy,
                    UseProxy = true,
                };
                AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);

2:在 appsettings.json

添加
"defaultProxy": {
    "proxyaddress": "<your IP here>"
  },