简体   繁体   中英

Wait on a task invoked in a delegate

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?

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM