3

我正在编写一些 MVC4 异步控制器代码,并且遇到了一个问题,即我异步调用了两个长时间运行的 Web 服务,而第二个调用似乎在错误的线程上。

这是代码片段:

public async Task<ActionResult> AmendDetails(Model model) 
{
    ClientMaintenanceClient clientService = new ClientMaintenanceClient();
    UpdateResponse clientResponse = await clientService.GetForUpdateAsync(clientService.CreateRequest(model.Id));

    StaticDataEnquiryClient staticService = new StaticDataEnquiryClient();
    DataResponse staticResponse = await staticService.GetPayMethodsAsync(staticService.CreateRequest());

    ...
}

本质上,对 CreateRequest() 的调用将从 HttpContext 中查找会话 id,并创建一个形成的 WCF 请求对象,用于调用服务。

然而,在执行时,第一次调用发生得很好,但是第二次异步调用失败,因为 HttpContext 为空,这会让我相信我现在在不同的线程上。

当我在 MVC3 和 .Net4.5 之前执行此操作时,我必须在通过 AsyncManager(使用 EAP)从 Async 调用返回时手动同步线程,但我认为我不再需要使用 TAP 来执行此操作。

如果我使用下面的代码片段并行执行代码,问题就会消失。

public async Task<ActionResult> AmendDetails(Model model) 
{
    ClientMaintenanceClient clientService = new ClientMaintenanceClient();
    var clientTask = clientService.GetForUpdateAsync(clientService.CreateRequest(model.Id));

    StaticDataEnquiryClient staticService = new StaticDataEnquiryClient();
    var staticTask = staticService.GetPayMethodsAsync(staticService.CreateRequest());

    await Task.WhenAll(clientTask,staticTask); 
    UpdateResponse clientResponse = await clientTask;
    DataResponse staticResponse = await StaticTask;
    ...
}
  • 我假设在第一个片段中,第一个等待将进程移动到后台线程,因此当我到达第二个等待时,我仍然在后台线程上。HttpContext 将为空,因为我无法从该线程中获取它。

  • 我还假设在第二段代码中,我在第一次等待之前进行了所有 HTTPContext 查找,所以我从来没有看到 HTTPContext 为空,因为我从来没有从后台线程调用它。

谁能证实我上面的假设?我不想在我的代码中查看一个明显的错误,它稍后会回来咬我!

更新:

我决定在这里执行期间检查线程,看来第二次等待确实发生在与第一次等待不同的线程上。有趣的是,似乎HttpContext在第二次调用时不为空。HttpContext.Current为空。

我通过以下方式访问会话 ID:

HttpContext.Current.Session.SessionId

我猜我需要在第二次等待之前在某个地方同步一些东西,但我不确定是什么。

4

1 回答 1

4

您的代码绝对应该可以工作。既然您提到了 MVC 3,我假设这是一个升级项目。在这种情况下,请确保您的 web.config 中有以下内容:

<appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
于 2013-04-22T16:57:20.787 回答