1

I have a controller method which looks something like this:

[HttpPut, Route("cqs/command")]
public HttpResponseMessage Command([ValueProvider(typeof(HeaderValueProviderFactory))] string typeName)
{
    object reply = null;
    var code = HttpStatusCode.OK;
    try
    {
        var cmdObject = DeserializeRequest(typeName);
        var method = _commandMethod.MakeGenericMethod(type);
        method.Invoke(this, new object[] { request });
    }
    catch (Exception exception)
    {
        code = HttpStatusCode.InternalServerError;
        reply = exception;
    }

    var responseMsg = new HttpResponseMessage(code);
    if (reply != null)
    {
        responseMsg.Headers.Add("X-TypeName", reply.GetType().AssemblyQualifiedName);
        var replyJson = JsonConvert.SerializeObject(reply);
        responseMsg.Content = new StringContent(replyJson, Encoding.UTF8, "application/json");
    }
    return responseMsg;
}

Which invokes the following method:

private void ExecuteCommand<T>(T command) where T : Command
{
    var task = _commandBus.ExecuteAsync(command);
    task.Wait(TimeSpan.FromSeconds(10));
}

The reason to that is that the _commandBus only have a generic method which I need to invoke.

The problem is however that the ExecuteCommand seems to deadlock at some times. I can't figure out why. The ICommandBus.ExecuteAsync method will invoke other tasks using async/await, so it might be some kind of dead lock since WebApi uses a synchronization context? (await vs Task.Wait - Deadlock?)

So if I understand it all correctly, there might be two solutions:

  1. use async/await all the way. But how do I do that when invoking a method using MethodInfo?
  2. Change so that my invocation works with the synchronization context

I'm lost when it comes to both solutions. Can anyone help?

Community
  • 1
  • 1
jgauffin
  • 99,844
  • 45
  • 235
  • 372
  • The problem doesn't seem to come from invoking the delegate though, it comes from the fact that you're doing a blocking wait on the task, when you should be asynchronously waiting. – Servy Mar 03 '14 at 20:24

1 Answers1

5

Change ExecuteCommand<T> so that it looks like this (I'm assuming your actual code will do something on a timeout):

private async Task ExecuteCommandAsync<T>(T command) where T : Command
{
  var timeout = Task.Delay(TimeSpan.FromSeconds(10));
  var task = _commandBus.ExecuteAsync(command);
  await Task.WhenAny(task, timeout);
}

And make whatever calls it async Task as well. Then, when you invoke the method, you can do this:

var task = method.Invoke(this, new object[] { request }) as Task;
await task;
Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • That works for the Command execution. But the Query variant returns a generic task. What is the best way to handle that? – jgauffin Mar 03 '14 at 20:50
  • 2
    `Task` inherits from `Task`, so if you just want to `await` it you don't need to do anything else. If you need to return a result somehow, I'd recommend `dynamic`. – Stephen Cleary Mar 03 '14 at 20:55