Async Await Handler Deadlock
Asked Answered
I

2

7

I'm stuck in an Async deadlock and I can't figure out the correct syntax to fix it. I've looked at several different solutions, but can't seem to quite figure out what is causing the problem.

I am using Parse as a backend and trying to use a handler to write to the table. My handler looks something like:

public class VisitorSignupHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        //Get the user's name and email address
        var UserFullName = context.Request.QueryString["name"].UrlDecode();
        var UserEmailAddress = context.Request.QueryString["email"].UrlDecode();

        //Save the user's information
        var TaskToken = UserSignup.SaveUserSignup(UserFullName, UserEmailAddress);
        TaskToken.Wait();
        ....

    }

    public bool IsReusable { get { return false; } }
}

Then it is calling my middle tier:

public static class UserSignup
{
    public static async Task SaveUserSignup(string fullName, string emailAddress)
    {
        //Initialize the Parse client with the Application ID and the Windows key
        ParseClient.Initialize(AppID, Key);

        //Create the object
        var UserObject = new ParseObject("UserSignup")
                            {
                                {"UserFullName", fullName},
                                {"UserEmailAddress", emailAddress}
                            };

        //Commit the object
        await UserObject.SaveAsync();
    }
}

Although this seems to be getting stuck at Wait(). I was under the impression that Wait() would simply just wait for the task to complete, then return to normal operations. Is this not correct?

Initiatory answered 25/7, 2013 at 13:48 Comment(0)
C
14

You're running into a common deadlock problem that I describe on my blog and in a recent MSDN article.

In short, await by default will resume its async method inside of a captured "context", and on ASP.NET, only one thread is allowed into that "context" at a time. So when you call Wait, you are blocking a thread inside that context, and the await cannot enter that context when it is ready to resume the async method. So the thread in the context is blocked at Wait (waiting for the async method to complete), and the async method is blocked waiting for the context to be free... deadlock.

To fix this, you should go "async all the way". In this case, use HttpTaskAsyncHandler instead of IHttpHandler:

public class VisitorSignupHandler : HttpTaskAsyncHandler
{
  public override async Task ProcessRequestAsync(HttpContext context)
  {
    //Get the user's name and email address
    var UserFullName = context.Request.QueryString["name"].UrlDecode();
    var UserEmailAddress = context.Request.QueryString["email"].UrlDecode();

    //Save the user's information
    var TaskToken = UserSignup.SaveUserSignup(UserFullName, UserEmailAddress);
    await TaskToken;
    ....

  }
}
Cornwell answered 25/7, 2013 at 13:54 Comment(3)
Thank you! I read your blog prior to posting this and just couldn't quite figure out the syntax. This works great. Appreciate it.Initiatory
You're welcome! P.S. Give the TAP documentation a good read; there are some async conventions that would apply here, in particular renaming SaveUserSignup to SaveUserSignupAsync.Cornwell
Could you please help me on this one #54001797Raquel
D
1

Your problem is that you are mixing synchronous and async code. This can be done, but is tricky. Your best bet is to make your http handler async as well:

public class VisitorSignupHandler : HttpTaskAsyncHandler
    {
        public override async Task ProcessRequestAsync(HttpContext context)
        {
           //Get the user's name and email address
           var UserFullName = context.Request.QueryString["name"].UrlDecode();
           var UserEmailAddress = context.Request.QueryString["email"].UrlDecode();

           //Save the user's information
           await UserSignup.SaveUserSignup(UserFullName, UserEmailAddress);
..

        }
    }
Declivous answered 25/7, 2013 at 14:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.