Reputation: 498
We've got an ASP.NET MVC application that has a form for visiters to subscribe their details for a newsletter.
The method responsible for subscribing users is defined below. We also have a custom web API that we're contacting through this method.
public async Task<string> Subscribe(User user)
{
if (user== null) throw new ArgumentNullException("user");
var request = new RestRequest("subscribe", Method.POST)
{
RequestFormat = DataFormat.Json
};
request.AddBody(user);
// Service Url is defined further up the code.
var client = new RestClient(serviceUrl);
var response = await client.ExecuteTaskAsync<User>(request);
return response.Data.Id;
}
The code itself works as it returns the appropriate ID from the request and I have confirmed this. The issue is that on the website it's still loading as if the submit button from our newsletter is still processing.
I've got a sneaky suspicion that await is still waiting and therefore hasn't completed it's run but it's confusing me how the results have returned in our CMS but the website is still loading.
Does anyone have any idea?
Upvotes: 0
Views: 701
Reputation: 498
The reason why it seems that my contact form in the UI is stuck is because the method Subscribe is called in a method that doesn't utilize the async/await keywords.
public string Test(User user)
{
if (user == null) throw new ArgumentNullException("user");
Subscribe(user);
// Rest of the method...
}
The await waits for the Subscribe task to finish and continues. When the method continue's it will do so in a context.
Just as described in this post here:
In the first case, this context is a UI context (which applies to any UI except Console applications). In the second case, this context is an ASP.NET request context.
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.
So the Test method in this instance is using the RequestContext, calls the Subscribe method. The await starts in the UI context and while waiting it continues back to the RequestContext which it can't access because the Test method is currently using it. It ends in a deadlock. That's why the UI is stuck in loading.
Upvotes: 1
Reputation: 16348
Await doesn't block your method, but the action won't complete until you get the result from the remote server i.e until the task finishes. The point of await is to free CPU threads while waiting on I/O operations.
So, while you're awaiting the thread which handles your request is free to handle other requests. await is a backend optimization, for the UI client nothing changes.
Upvotes: 1