1

I am trying to call an async method from a synchronous library method and running in to problems. I'll start by showing some code.

public void Execute(RegisterUserCommand command)
{
    var user = new UserAccountEntity
    {
        UserName = command.EmailAddress,
        Email = command.EmailAddress,
    };

    var task = _userManager.CreateAsync(user, command.Password);

    var result = task.Result; // Causes deadlock

    if (!result.Succeeded)
        throw new CommandInvalidException("Command failed", result.Errors);
}

Calling task.Result is making my code deadlock.

After doing some research (including reading this) and some digging I now think I have a relatively good understanding of what causes the deadlock.

I am using the UserManager from asp .net Identity. I used dotPeek and found out that UserManager.CreateAsync calls UserValidator.ValidateAsync which will await some tasks without calling .ConfigureAwait(false).

  • Am I correct that this will cause task.Result to deadlock? How can I solve this deadlock when I have no control over the async method being called?
  • Is it ever possible to call .Result on a task returned from a library method that does not implement ConfigureAwait(false)?
  • The answer here says to "explicitly execute your async method in a thread pool thread and wait for it to finish". I will test this later today, but does this mean there is no way to fix my problem without me manually starting a new thread?
  • I think that the best solution to the problem would be to make my Execute method async, is this assumption correct? I'd rather wait with this solution though and try to fix it without using async first.
Community
  • 1
  • 1
andreas
  • 505
  • 1
  • 7
  • 16
  • Can't you just call `ConfigureAsync(false)` on `task` yourself? – MarcinJuraszek Jul 30 '14 at 21:41
  • I've tried that, didn't seem to work. Not sure why. – andreas Jul 31 '14 at 05:54
  • I edited the question. I made it more clear what information I am looking for.I don't think it is a duplicate anymore, in my case I have no control over the async method being called. – andreas Jul 31 '14 at 17:46
  • You shouldn't be making this method synchronous. It should be asynchronous. That, or you should be calling entirely synchronous methods to do this work, rather than trying to use half and half. – Servy Jul 31 '14 at 17:55
  • "is no way to fix my problem without me manually starting a new thread?" Yes, that is correct. The async continuation needs to be able to use a thread once the I/O event returns. If it is associated with the main thread, then the continuation can't run whilst the main thread is blocked on `task.Result`. It isn't possible to work out which thread the Task wants to run on, normally you can use `.ConfigureAwait(false)` to override that...but it depends on how its written. – Aron Jul 31 '14 at 18:00
  • @Servy I realize I probably shouldn't do this, but if I change my Execute method to return a Task and use await, I have to do the same for all other tasks implementing my ICommand interface. That is why I just want to get it working now, and then make the proper fix later. – andreas Jul 31 '14 at 18:49
  • @Aron I guess you are right. I will solve my issue now by using `Task.Run(() => _userManager.CreateAsync(user, command.Password)).Result`. This seems to work. Thanks! – andreas Jul 31 '14 at 18:50
  • @andreas That's correct, you either need to make the whole process asynchronous, or none of it. It needs to be one or the other, not half and half. – Servy Jul 31 '14 at 18:53
  • @andreas That's a *terrible* solution to the problem. You shouldn't be doing that. If you don't want to make the whole process asynchronous, then make none of it asynchronous. – Servy Jul 31 '14 at 18:54
  • @Servy I have no choice while using [asp.net identity](http://msdn.microsoft.com/en-us/library/dn613059(v=vs.108).aspx). There is only the Async method for creating a user. I will start updating everything to be async soon and will then be able to get rid of that solution. – andreas Jul 31 '14 at 19:13

0 Answers0