我目前正在实施调用内部服务的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()
任务完成了。
鉴于内部服务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();
}
答案 0 :(得分:5)
您的问题是,如果您不使用Result
,ContinueWith()
将返回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中引入的一些类型,但没有其他原因需要新的运行时。
但是,如果您正在使用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?