C# Asp.net WebAPI:中止(取消)请求
首先,如果你们中有人在WebAPI控制器中执行请求取消之类的操作(可能也适用于MVC),那么这是一个讨论 我特别想说的是这样一个场景: 客户端(通常是浏览器)启动请求,导航到别处或更一般的位置,出于任何原因中止请求。现在,请求在客户端被中止,不再被考虑。但在服务器端,请求仍在执行,通常可能会做两件特别有趣的事情:C# Asp.net WebAPI:中止(取消)请求,c#,asp.net,asp.net-mvc,asp.net-web-api,C#,Asp.net,Asp.net Mvc,Asp.net Web Api,首先,如果你们中有人在WebAPI控制器中执行请求取消之类的操作(可能也适用于MVC),那么这是一个讨论 我特别想说的是这样一个场景: 客户端(通常是浏览器)启动请求,导航到别处或更一般的位置,出于任何原因中止请求。现在,请求在客户端被中止,不再被考虑。但在服务器端,请求仍在执行,通常可能会做两件特别有趣的事情: 进行(繁重的)数据库查询 给另一个服务打一个(沉重的)服务电话 最终一切都是徒劳的(至少当它是一个无副作用的读取操作时) 在这种情况下,是否有人负责取消正在进行的查询/服务呼叫 我
- 进行(繁重的)数据库查询
- 给另一个服务打一个(沉重的)服务电话
CancellationToken
(即使我无法让它工作,因此从客户端中止时确实请求取消)。
理论上,这个
CancellationToken
需要传递到所有较低的层,以处理数据库和服务调用的可能取消。虽然在编写WebAPI时不直接支持取消,但OWIN API绝对支持取消。如果您使用的是WebAPI 2.0,那么您将在OWIN之上运行,并且能够使用扩展方法通过Microsoft wrappers访问上下文
使用通过OwinRequest
属性公开的CancellationToken
值方便地传播取消。您可以将这一切放在一起,以在控制器方法中获得令牌:
public async Task Get()
{
var cancellation = Request.GetOwinContext().Request.CallCancelled;
await database.FooAsync(cancellation);
}
不过这很难看。您将不得不在每个需要处理取消的方法中进行此调用,并且它与WebAPI将为您提供此CancellationToken
的建议的未来不兼容。相反,如果我们能把它变成一个参数,不是更好吗
public async Task Get(CancellationToken cancellation)
{
await database.FooAsync(cancellation);
}
为此,您可以创建一个自定义参数绑定,从OWIN上下文中获取CancellationToken
:
public class OwinCancellationTokenBinding : HttpParameterBinding
{
public OwinCancellationTokenBinding(HttpParameterDescriptor parameter)
: base(parameter)
{
}
public override Task ExecuteBindingAsync(
ModelMetadataProvider metadataProvider,
HttpActionContext actionContext,
CancellationToken cancellationToken)
{
actionContext.ActionArguments[Descriptor.ParameterName]
= actionContext.Request.GetOwinContext().Request.CallCancelled;
return Task.FromResult<object>(null);
}
}
此规则匹配类型为
CancellationToken
的任何参数。您可以在此处创建与您希望提供此值的参数匹配的任何规则。这可能无法完全回答您的问题,但看看它确实听起来很有趣。似乎可以使用CancellationToken作为参数(我知道这一点),特别是框架取消了它。谢谢!但这不是开箱即用的支持吗?当CancellationToken用作最后一个参数时,它由webapi管道设置。参考:(我希望这个链接继续工作)那么看起来我一直在处理旧信息。好吧,你的想法已经实现了!微软有很多聪明的家伙在思考这些话题,请骄傲!
config.ParameterBindingRules.Add(p
=> p.ParameterType == typeof(CancellationToken)
? new OwinCancellationTokenBinding (p)
: null);