【问题标题】:Don't return from action until task ends在任务结束之前不要从行动中返回
【发布时间】:2016-12-14 10:24:19
【问题描述】:

我有点迷失在ASP.NET Web API 操作中的异步任务。我有一个动作:

[HttpPost]
public async Task<HttpResponseMessage> Restart()
{
    await AspManager.Restart();

    return Request.CreateResponse(HttpStatusCode.OK, new { result = "Success", message = "IIS site successfully restarted" });
}

重新启动可能会运行很长时间,我想等待它然后返回响应。这是长时间运行的代码:

public static async Task<Task> Restart()
{
    var client = new Client("...");
    CheckApiKey(client);

    var task = Task.Factory.StartNew(async () =>
    {
        client.Stop();

        await Task.Delay(5 * 1000);

        throw new BusinessException("test");
        client.Start();
    });

    return await task;
}

所以在主要的Restart 方法中,我正在检查一个密钥,然后我应该停止服务,等待 5 秒并启动服务。在此工作完成之前,控制器的操作不应返回。但问题是动作返回并在 5 秒后抛出 BusinessException

【问题讨论】:

  • 您在任务中抛出了一个新异常。为什么你会期待别的?
  • 嗯,那次投掷是为了测试。我描述的问题是我需要等到客户端停止并启动然后返回http响应。但是在这里它首先返回,然后才抛出异常。

标签: c# asp.net-web-api async-await


【解决方案1】:

您的方法是async Task&lt;Task&gt;,您正在启动一个任务并返回它。这意味着您要返回的任务刚刚开始。

关键点是:您正在等待任务创建,而不是执行。

将您的方法签名更改为“async void”,然后从await Task.Factory.StartNew(() => versus Task.Start; await Task; 使用Task.Run()

public async Task Restart()
{
    // ...

    await Task.Run(async () =>
    {
        client.Stop();

        await Task.Delay(5 * 1000);

        client.Start();
    });
}

【讨论】:

  • 今天你是我的英雄 :) 谢谢!
【解决方案2】:

Task.Factory.StartNew is a dangerous API,正如我在博客中解释的那样。您遇到的问题是它不理解 async lambdas。 (还有其他问题)。

但是,使用Task.Run 不是一个合适的解决方案。它在 ASP.NET 上适得其反。您应该只使用 await 本身:

public static async Task<Task> RestartAsync()
{
  var client = new Client("...");
  if (CheckApiKey(client))
    return;

  client.Stop();
  await Task.Delay(TimeSpan.FromSeconds(5));
  client.Start();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-25
    • 2016-08-31
    • 1970-01-01
    • 2020-01-22
    • 2017-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多