合并.NET 4.0任务/不同类型的延续

时间:2012-05-03 02:40:05

标签: .net c#-4.0 asynchronous task async-await

我目前正在实施调用内部服务的System.Web.Http.IActionFilter,以确定当前请求是否可以继续。我遇到的问题是根据Task<T1>封装的一段逻辑返回Task<T2>

一个例子可能有所帮助。

内部服务API使用Tasks实现。使用 .NET 4.5 的async / await:

这个逻辑是微不足道的
public async Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
    UserAuthenticationResult authResult = await HitInternalServiceAsync();

    if (!authResult.IsAuthenticated)
    {
        throw new HttpResponseException("User is not authenticated", HttpStatusCode.Unauthorized);
    }

    return await continuation();
}

然而,使用 .NET 4.0 ;

中的旧Task API会更困难
public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
    return HitInternalServiceAsync()
            .ContinueWith(t1 => {
                UserAuthenticationResult authResult = t1.Result;

                if (!authResult.IsAuthenticated)
                {
                    throw new HttpResponseException("User is not authenticated", HttpStatusCode.Unauthorized);
                }

                //Hack hack - this blocks the thread until the task retuned by continuation() completes
                return continuation().Result;
            });
}

当身份验证检查成功时出现困难部分 - 然后我想等待continuation函数返回的任务。

使用.NET 4.0看起来我在等待continuation()任务完成时显式阻塞,而不是在我的任务时指示Tasks API自动继续执行continuation()任务完成了。

问题:这是在.NET 4.0中实现此行为的唯一方法吗?

鉴于内部服务API足够复杂,我可以很容易地看到等待其他任务的任务数量快速增加。

编辑:看起来上面的 4.0 代码也不可行 - 因为延续lambda不会在像HttpContext这样的ASP.NET线程上下文服务中执行。目前无法使用。更好的实施将是......

public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
    Task<UserAuthenticationResult> authResultTask = HitInternalServiceAsync();

    var authResult = authResultTask.Result;

    if (!authResult.IsAuthenticated)
    {
        throw new HttpResponseException("User is not authenticated", HttpStatusCode.Unauthorized);
    }

    return continuation();
}

3 个答案:

答案 0 :(得分:5)

您的问题是,如果您不使用ResultContinueWith()将返回Task<Task<HttpResponseMessage>>,而不会返回您需要的Task<HttpResponseMessage>

幸运的是,已有一种方法可以将任何Task<Task<T>>转换为Task<T>Unwrap()。所以只需return continuation(); lambda中的ContinueWith(),然后在结果上调用Unwrap()

如果要在ASP.NET上下文中执行继续,可以使用TaskScheduler.FromCurrentSynchronizationContext()

答案 1 :(得分:3)

  

问题:这是在.NET 4.0中实现此行为的唯一方法吗?

async / await是C#5.0功能,而不是.NET 4.5功能。它确实利用了.NET 4.5中引入的一些类型,但没有其他原因需要新的运行时。

如果你使用的是VS2010(C#4.0),那么svick的答案是最好的。

但是,如果您正在使用VS11 Beta(C#5.0),还有另一种选择:您可以使用async targeting pack编写在.NET 4.0上运行的async / await代码。目标包具有.NET 4.0的新类型。

答案 2 :(得分:1)

而不是continuation()。结果 使用continuation()。Wait()

task.wait是阻止任务的适当方式。

根据MSDN文档, Task.Wait方法:等待任务完成执行。

http://msdn.microsoft.com/en-us/library/dd235635.aspx

Folowing似乎是相关问题,即答案 Do the new C# 5.0 'async' and 'await' keywords use multiple cores?