2013-04-22 68 views
3

我正在写一些MVC4异步控制器代码,并且遇到了一个问题,因此我会向两个长时间运行的Web服务异步调用,而第二个调用看起来是在错误的线程中。在多个等待场景中的HTTPContext

这里是代码片段:

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,并创建一个呼叫中使用该服务所形成的WCF请求对象。

然而在执行时,第一个调用很好,但第二个异步调用失败,因为HttpContext为null,这会导致我相信我现在处于不同的线程。

当我在MVC3和.Net4.5之前完成此操作时,必须通过AsyncManager(使用EAP)从异步调用中返回时手动同步线程,但我认为我不再需要这样做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; 
    ... 
} 
  • 我假设的是,在第一个片段,第一个是AWAIT过程的时候我到了第二的await移动到后台线程,等于是,我仍然在后台线程。 HttpContext将为空,因为我无法从该线程获得它。

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

任何人都可以证实我的上述假设?我不想在我的代码中看到一个明显的错误,它会在以后回来并咬我!

更新:

我决定在这里检查执行过程中的线程,它出现第二的await确实在不同的线程比第一的await发生。有趣的是,在第二次调用时,看起来HttpContext不为空。它是空的HttpContext.Current

我通过访问会话ID:

HttpContext.Current.Session.SessionId 

我猜我需要第二的await在什么地方同步的东西,但我不知道是什么。

+0

在ASP.NET中,线程不喜欢GUI应用程序。你的第二个调用应该在正确的上下文中执行,同时设置HttpContext。 (换句话说,我不知道你的代码有什么问题。) – svick 2013-04-22 16:53:48

回答

4

你的代码一定是应该工作。自从你提到MVC 3以来,我假设这是一个升级项目。在这种情况下,请确保你在你的web.config以下:

<appSettings> 
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> 
</appSettings> 
+0

嗯...是的工作。它做了什么?MSDN陈述道:“为启用WebSocket的应用程序设置此兼容性开关是必需的,在Web窗体页面中使用基于任务的异步,以及对于某些其他异步行为。”这是否是某些其他异步行为? – Nick 2013-04-22 17:11:09

+0

说实话,我并不是100%确定为什么你的代码在新的(任务友好的)'AspNetSynchronizationContext'和旧的'LegacyAspNetSynchronziationContext'之间工作不同。我怀疑,与传统的,它是太早完成请求 - 但我会认为'异步'MVC控制器会阻止... – 2013-04-22 17:38:40