C# Web Api请求超时?
与MVC一样,WebApi在异步ASP.NET管道上运行,这意味着C# Web Api请求超时?,c#,asp.net,asp.net-web-api,asp.net-web-api2,C#,Asp.net,Asp.net Web Api,Asp.net Web Api2,与MVC一样,WebApi在异步ASP.NET管道上运行,这意味着 在MVC中,我使用[AsyncTimeout]过滤器,WebApi没有这个过滤器。那么如何在WebApi中超时请求呢?使用WebApi,您通常会在客户端而不是服务器端处理超时。这是因为,而且: 取消HTTP请求的方法是直接在HttpClient上取消它们。原因是多个请求可以在单个HttpClient中重用TCP连接,因此您无法安全地取消单个请求而不可能影响其他请求 您可以控制请求的超时时间——如果我没有记错的话,我认为它在Htt
在MVC中,我使用
[AsyncTimeout]
过滤器,WebApi没有这个过滤器。那么如何在WebApi中超时请求呢?使用WebApi,您通常会在客户端而不是服务器端处理超时。这是因为,而且:
取消HTTP请求的方法是直接在HttpClient上取消它们。原因是多个请求可以在单个HttpClient中重用TCP连接,因此您无法安全地取消单个请求而不可能影响其他请求
您可以控制请求的超时时间——如果我没有记错的话,我认为它在HttpClientHandler上
如果您真的需要在API端本身实现超时,我建议您创建一个线程来执行您的工作,然后在一段时间后取消它。例如,您可以将其放入任务中,使用任务创建“超时”任务。等待并使用任务。等待任何任务返回。这可以模拟超时
同样,如果您正在执行特定的操作,请检查它是否已经支持超时。通常,我会从我的WebAPI执行一个HttpWebRequest
,并指定它的属性。基于Mendhak的建议,可以做你想做的事情,尽管不是你想做的那样,也不需要经历很多困难。在不使用过滤器的情况下执行,可能会出现如下情况:
public class ValuesController : ApiController
{
public async Task<HttpResponseMessage> Get( )
{
var work = this.ActualWork( 5000 );
var timeout = this.Timeout( 2000 );
var finishedTask = await Task.WhenAny( timeout, work );
if( finishedTask == timeout )
{
return this.Request.CreateResponse( HttpStatusCode.RequestTimeout );
}
else
{
return this.Request.CreateResponse( HttpStatusCode.OK, work.Result );
}
}
private async Task<string> ActualWork( int sleepTime )
{
await Task.Delay( sleepTime );
return "work results";
}
private async Task Timeout( int timeoutValue )
{
await Task.Delay( timeoutValue );
}
}
[TimeoutFilter( 10000 )]
public string Get( )
{
Thread.Sleep( 5000 );
return "Results";
}
然后可以这样使用:
public class ValuesController : ApiController
{
public async Task<HttpResponseMessage> Get( )
{
var work = this.ActualWork( 5000 );
var timeout = this.Timeout( 2000 );
var finishedTask = await Task.WhenAny( timeout, work );
if( finishedTask == timeout )
{
return this.Request.CreateResponse( HttpStatusCode.RequestTimeout );
}
else
{
return this.Request.CreateResponse( HttpStatusCode.OK, work.Result );
}
}
private async Task<string> ActualWork( int sleepTime )
{
await Task.Delay( sleepTime );
return "work results";
}
private async Task Timeout( int timeoutValue )
{
await Task.Delay( timeoutValue );
}
}
[TimeoutFilter( 10000 )]
public string Get( )
{
Thread.Sleep( 5000 );
return "Results";
}
这适用于简单类型(例如字符串),在Firefox中为我们提供:Results
,但正如您所见,序列化并不理想。就序列化而言,将自定义类型与此完全相同的代码一起使用会有点问题,但通过一些工作,这可能在某些特定场景中很有用。动作参数以字典的形式出现而不是以数组的形式出现,这也会在参数顺序方面带来一些问题。显然,得到真正的支持会更好
就vNext而言,由于MVC和API控制器正在统一,他们很可能计划为Web API添加服务器端超时功能。如果他们这样做,则很可能不会通过System.Web.Mvc.AsyncTimeoutAttribute
类,因为他们会显式删除对System.Web
的依赖关系
到今天为止,向project.json
文件添加System.Web.Mvc
条目似乎还不起作用,但这很可能会改变。如果是这样的话,虽然您将无法将新的云优化框架与此类代码一起使用,但您可能可以对只打算与完整的.NET framework一起运行的代码使用AsyncTimeout
属性
值得一提的是,这是我尝试添加到project.json
中的内容。也许一个特定的版本会让它更快乐
"frameworks": {
"net451": {
"dependencies": {
"System.Web.Mvc": ""
}
}
}
对它的引用确实会显示在解决方案资源管理器的“引用”列表中,但它会以黄色感叹号表示问题。当此引用保留时,应用程序本身返回500个错误。为了让您的生活更轻松,请在基本控制器中添加以下方法:
protected async Task<T> RunTask<T>(Task<T> action, int timeout) {
var timeoutTask = Task.Delay(timeout);
var firstTaskFinished = await Task.WhenAny(timeoutTask, action);
if (firstTaskFinished == timeoutTask) {
throw new Exception("Timeout");
}
return action.Result;
}
受保护的异步任务RunTask(任务操作,int超时){
var timeoutTask=Task.Delay(超时);
var firstTaskFinished=等待任务.WhenAny(超时任务,操作);
如果(firstTaskFinished==超时任务){
抛出新异常(“超时”);
}
返回动作。结果;
}
现在,从基本控制器继承的每个控制器都可以访问RunTask方法。现在,在API中调用RunTask方法,如下所示:
[HttpPost]
public async Task<ResponseModel> MyAPI(RequestModel request) {
try {
return await RunTask(Action(), Timeout);
} catch (Exception e) {
return null;
}
}
private async Task<ResponseModel> Action() {
return new ResponseModel();
}
[HttpPost]
公共异步任务MyAPI(请求模型请求){
试一试{
返回等待运行任务(Action(),超时);
}捕获(例外e){
返回null;
}
}
专用异步任务操作(){
返回新的ResponseModel();
}
对于需要超时的每个端点,通过管道输送一个取消令牌,例如:
[HttpGet]
public Task<Response> GetAsync()
{
var tokenSource = new CancellationTokenSource(_timeoutInSec * 1000);
return GetResponseAsync(tokenSource.Token);
}
[HttpGet]
公共任务GetAsync()
{
var tokenSource=新的CancellationTokenSource(_timeoutInSec*1000);
返回GetResponseAsync(tokenSource.Token);
}
很抱歉,这并不能真正回答我的问题。我的Api由浏览器中的javascript使用,无法启用跨浏览器工作的请求超时。这就是为什么我要寻找与[AsyncTimeout]等效的WebApi,以便我可以在服务器上执行它。请参阅引号后的位-您可以使用Task.WaitAny来执行它,主任务在一个线程中,而“wait”超时任务在另一个线程中。如果超时任务提前返回,那么您可以立即返回。我理解,谢谢您的回答。但我要寻找的是一个可以像MVC中的[AsyncTimeout]一样全局应用的解决方案。我认为它在我正在回顾的vNext中得到了支持。我相信你是对的,它将在vNext DalSoft中得到支持。不仅是[AsyncTimeout]的添加,还有许多我们在与常规ViewController进行比较时无法访问的属性。请检查这篇文章,downvoter是否愿意解释原因+1这是一个非常全面的概述。