【问题标题】:How to timeout a request in ASP.net MVC web api如何在 ASP.net MVC web api 中使请求超时
【发布时间】:2019-09-03 21:25:46
【问题描述】:

我的应用程序正在运行 ASP.Net MVC 5.2.2 并托管在 IIS 7 集成管道上。当请求的持续时间超过 3 分钟时,我希望超时请求。设置httpRuntime.executionTimeout 没有帮助。

我有其他 ASP.Net 应用程序在 IIS 6 classic mode 中运行。当请求持续时间超过 httpRuntime.executionTimeout 值时,Asp.Net 会自动抛出 ThreadAbortException

我试图查看 ASP.Net 源代码并找到 RequestTimeoutManager。它基本上跟踪所有初始化的 HttpRequest,后台任务中止超过超时持续时间的请求。 RequestTimeoutManager 是否适用于 ASP.Net MVC Web Api?如果不是,如何实现类似的东西。

我的应用程序中典型 Http 请求的堆栈跟踪

   at MyApp.Api.Controllers.Controller.GetDetails(String Id) 
   at lambda_method(Closure , Object , Object[] )
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.<GetExecutor>b__c(Object instance, Object[] methodParameters)
   at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)
   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.<>c__DisplayClass3.<InvokeActionAsync>b__0()
   at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)
   at System.Web.Http.Controllers.ApiControllerActionInvoker.InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
   at System.Web.Http.Filters.ActionFilterAttribute.System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func`1 continuation)
   at System.Web.Http.Filters.ActionFilterAttribute.System.Web.Http.Filters.IActionFilter.ExecuteActionFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func`1 continuation)
   at System.Threading.Tasks.TaskHelpersExtensions.ThenImpl[TTask,TOuterResult](TTask task, Func`2 continuation, CancellationToken cancellationToken, Boolean runSynchronously)
   at System.Threading.Tasks.TaskHelpersExtensions.Then[TOuterResult](Task task, Func`1 continuation, CancellationToken cancellationToken, Boolean runSynchronously)
   at System.Web.Http.ApiController.<>c__DisplayClass3.<ExecuteAsync>b__0()
   at System.Web.Http.Filters.AuthorizationFilterAttribute.System.Web.Http.Filters.IAuthorizationFilter.ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func`1 continuation)
   at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)
   at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at MyApp.Common.MyAppExceptionHandler.<>n__0(HttpRequestMessage request, CancellationToken cancellationToken)
   at MyApp.Common.MyAppExceptionHandler.<SendAsync>d__1.MoveNext() in C:\MyApp_source\Components\MyAppExceptionHandler.cs
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.Start[TStateMachine](TStateMachine& stateMachine)
   at MyApp.Common.MyAppExceptionHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.HttpServer.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.WebHost.HttpControllerHandler.BeginProcessRequest(HttpContextBase httpContextBase, AsyncCallback callback, Object state)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
   at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error)
   at System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb)
   at System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
   at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
   at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)

【问题讨论】:

  • 如果使用 async-await,那么您始终可以在异步代码中使用取消令牌,您也可以将来自中间件的请求短路。

标签: asp.net-mvc asp.net-web-api


【解决方案1】:

您可以使用自定义属性覆盖AsyncManager 中的超时值

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class CustomAsyncTimeoutAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException(nameof(filterContext));
        }

        if (!(filterContext.Controller is IAsyncManagerContainer managerContainer))
        {
            throw new InvalidOperationException("Action Filter failed");
        }

        managerContainer.AsyncManager.Timeout = 180000;
        base.OnActionExecuting(filterContext);
    }
}

或者你为什么不能使用[AsyncTimeout(180000)]

【讨论】:

  • 设置 ScriptTimeout、executionTimeout、requestTimeout 值在 MVC 异步管道中不起作用。 stackoverflow.com/a/27342836/1219543
  • 有趣。我改变了答案。也许它会帮助你。还是您在寻找 IIS 端示例
【解决方案2】:

您可以在 2 个正在运行的任务之间创建竞赛一个用于主要操作另一个用于首选超时(例如 3 * 60,000 ms = 180,000 ms) 通过以下代码:

public async Task<HttpResponseMessage> Get() 
{
    var _task = this.DoTask(2000); //your operation required time
    var _timeout = this.SetTimeout(180000); //equal to 3 minutes
    var _finishedTask = await Task.WhenAny(_timeout, _task);
    if (_finishedTask == _timeout)
        return this.Request.CreateResponse(HttpStatusCode.RequestTimeout); //timeout
    else
        return this.Request.CreateResponse(HttpStatusCode.OK, _task.Result); //Ok
}

private async Task<string> DoTask(int duration)
{
    await Task.Delay(duration);
    return "work results";
}

private async Task SetTimeout(int ms)
{
    await Task.Delay(ms);
}

我已经用ApiController 作为基类进行了测试并且工作正常。 较早完成的任务赢得比赛并决定Api结果

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-15
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 2017-12-21
    • 1970-01-01
    • 2020-02-20
    • 1970-01-01
    相关资源
    最近更新 更多