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

Ben*_*Fox 3 .net asynchronous task async-await c#-4.0

我目前正在实现一个System.Web.Http.IActionFilter调用内部服务来确定当前请求是否可以继续.我遇到的问题是返回一个Task<T1>基于a封装的逻辑Task<T2>.

一个例子可能有帮助.

内部服务API使用Tasks实现.使用.NET 4.5的异步/等待逻辑是微不足道的:

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();
}
Run Code Online (Sandbox Code Playgroud)

但是,使用.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;
            });
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

给定一个足够复杂的内部服务API,我可以很容易地看到等待其他任务的任务数量快速增加.

编辑:看起来上面的4.0代码也不可行 - 因为延续lambda不在ASP.NET线程上下文服务中执行,如HttpContext.Current不可用.更好的实施将是......

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();
}
Run Code Online (Sandbox Code Playgroud)

svi*_*ick 5

你的问题是,如果你不使用Result,ContinueWith()将返回Task<Task<HttpResponseMessage>>而不是Task<HttpResponseMessage>你需要的.

幸运的是,已经存在一种将any转换Task<Task<T>>Task<T>:的方法Unwrap().所以只是return continuation();ContinueWith()lambda然后调用Unwrap()结果.

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