我正在编写一些 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
我猜我需要在第二次等待之前在某个地方同步一些东西,但我不确定是什么。