I am writing some MVC4 async controller code, and am getting an issue whereby I call out to two long running web services asynchronously, and the second of the calls appears to be on the wrong thread.
Here is the code snippet:
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());
...
}
Essentially, the calls to CreateRequest() will look up the session id out of the HttpContext, and create a formed WCF request object used in the call to the service.
On execution however, the first call occurs fine, however the second async call fails because the HttpContext is null, which would lead me to believe I'm now on a different thread.
When I did this in MVC3, and prior to .Net4.5, I had to manually sync the threads when returning from the Async calls via AsyncManager (using EAP), but I thought I no longer had to do that with TAP.
If I execute the code in parallel, using the code snippet below, the issue goes away.
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;
...
}
I am presuming that in the first snippet, the first await is moving the process onto a background thread, and so therefore by the time I get to the second await, I'm still on the background thread. The HttpContext is going to be null because I cant get to it from that thread.
I am also presuming that in the second snippet of code, I am doing all of the HTTPContext lookups before the first await, so I never see the HTTPContext as null, as I never call it from the background thread.
Can anyone confirm my assumptions above? I don't want to be looking over a glaring error in my code which will come back and bite me later!
Update:
I decided to check the threads during execution here, and it appears that the second await does indeed occur on a different thread than the first await. The interesting thing is that it appears that the HttpContext is not null on the second call. It is the HttpContext.Current that is null.
I am accessing the session id via:
HttpContext.Current.Session.SessionId
I am guessing I need to sync something somewhere before the second await, but I'm not sure what.
Your code definitely should work. I'm assuming since you mentioned MVC 3 that this is an upgraded project. In that case, please ensure you have the following in your web.config:
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With