如何在超时后取消异步WebApi操作?

3
使用ASP.Net WebAPI,我有一个控制器,其中包含类似于以下内容的异步操作:
[HttpPost]
public async Task<string> DoSomething(string foo)
{
  var result = await MyAsynchronousTask(foo);
  return result;
}

这个控制器所做的不重要。重要的是它正在使用新的.NET 4.5异步/等待支持等待异步任务。

问题:如何告诉它在指定时间后超时?我不一定想取消该任务,我只想防止调用者永远挂起。(尽管我也很想以两种方式看到它。)

1个回答

7

我在LINQPad中使用“C#程序”选项制作了一个版本 - 它可以编译并运行,输出2行,显示超时和成功两种情况:

00:00:05超时

成功获取foo的结果

这是代码片段:

void Main()
{
    CallGetStringWithTimeout(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10)).Wait();
    CallGetStringWithTimeout(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(0)).Wait();
}

public async Task CallGetStringWithTimeout(TimeSpan callTimeout, TimeSpan callAddedDelay)
{
    var myTask = GetStringAsync(callAddedDelay);
    await Task.WhenAny(Task.Delay(callTimeout), myTask);
    if (myTask.Status == TaskStatus.RanToCompletion)
    {
        Console.WriteLine ("Successfully got result of {0}", await myTask);
    }
    else
    {
        Console.WriteLine ("Timeout of {0} expired", callTimeout);
    }
}

public async Task<string> GetStringAsync(TimeSpan addedDelay)
{
    await Task.Delay(addedDelay);
    return "foo";
}

然而,“正常”的方法是使用CancellationTokenSource并将超时时间指定为构造函数参数。如果您已经有一个CancellationTokenSource,您可以在其上调用CancelAfter方法,它将为指定的超时时间安排取消。

这不起作用是因为我有一个Task<string>,而Task.Delay只是一个Task。我需要以某种方式进行包装,我想。你们有什么建议吗? - Matt Johnson-Pint
我想我明白了。Task.Delay(timeout).ContinueWith<string>(x=> null) 似乎可以工作。这是一个合理的方法吗,还是有更简洁的方式? - Matt Johnson-Pint
不确定为什么需要包装它 - Task.WhenAny 可以很好地处理它,只是将其视为非泛型任务。如果状态显示它运行良好,那么您可以访问 Result 属性,或等待它,或者做任何其他操作(您在条件语句中已经完成了它,所以不用担心阻塞)。 - James Manning
我会将其充实为更完整的示例,希望这能有所帮助。 :) - James Manning
尝试一下。如果没有 .ContinueWith<string>(x=>null),它将无法编译。非泛型任务和泛型任务<T>之间存在类型不匹配。 - Matt Johnson-Pint
@Matt - 我放置的新代码编译和运行都很好 - 我有什么误解吗? - James Manning

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接