在QueueBackgroundWorkItem上实现WhenAll

时间:2016-06-26 15:15:40

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

我需要在ASP.NET WebAPI中生成一些长时间运行的任务,我选择使用QueueBackgroundWorkItem来执行此操作。

我的问题是 -

我需要用这些任务实现WhenAll机制,这意味着 - 我需要知道某些任务何时完成,然后执行其他任务。

如何使用QueueBackgroundWorkItem完成?我找不到办法,因为它返回void,并接受Action

谢谢!

2 个答案:

答案 0 :(得分:1)

您可以使用TaskCompletionSource创建一个这样的辅助方法:

public static Task RunViaQueueBackgroundWorkItem(Action<CancellationToken> action)
{
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
    HostingEnvironment.QueueBackgroundWorkItem((ct) =>
    {
        try
        {
            action(ct);

            if (ct.IsCancellationRequested)
                tcs.TrySetCanceled();
            else
                tcs.TrySetResult(0);
        }
        catch (Exception ex)
        {
            tcs.TrySetException(ex);
        }
    });

    return tcs.Task;
}

此方法将返回在操作完成后将完成的任务。请注意,它处理在调用操作期间发生异常的情况。如果要求取消,它也会处理此案件。

以下是如何使用它的示例:

public async Task<string> Get(int id)
{
    var t1 = RunViaQueueBackgroundWorkItem(ct => DoSomeTask1(ct));
    var t2 = RunViaQueueBackgroundWorkItem(ct => DoSomeTask2(ct));

    await Task.WhenAll(t1, t2);

    //...
}

为了完整性,这里是QueueBackgroundWorkItem的另一个重载的辅助方法:

public static Task RunViaQueueBackgroundWorkItem(Func<CancellationToken,Task> asyncAction)
{
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
    HostingEnvironment.QueueBackgroundWorkItem(async (ct) => 
    {
        try
        {
            await asyncAction(ct);

            if (ct.IsCancellationRequested)
                tcs.TrySetCanceled();
            else
                tcs.TrySetResult(0);
        }
        catch (Exception ex)
        {
            tcs.TrySetException(ex);
        }
    });

    return tcs.Task;
}

答案 1 :(得分:1)

  

我需要用这些任务实现一个WhenAll机制,这意味着 - 我需要知道某些任务何时完成,然后执行其他任务。

你应该做的是写出你需要的逻辑:

async Task MyWorkAsync(CancellationToken token)
{
  var t1 = Work1Async(token);
  var t2 = Work2Async(token);
  await Task.WhenAll(t1, t2);
  ... // More work
}

然后只需拨打QueueBackgroundWorkItem一次:

HostingEnvironment.QueueBackgroundWorkItem(token => MyWorkAsync(token));