为什么我的动作方法没有超时?

Pro*_*ofK 17 asp.net-mvc http asp.net-mvc-4

我有以下控制器:

[TimeoutFilter]
public abstract class BaseController: Controller
{
}

public class IntegrationTestController : BaseController
{
    [HttpGet]
    public ActionResult TimeoutSeconds()
    {
        return Content(HttpContext.Server.ScriptTimeout.ToString(CultureInfo.InvariantCulture));
    }

    [HttpGet]
    public ActionResult ForceTimeout()
    {
        var timeoutWindow = TimeoutFilter.TimeoutSeconds;
        Thread.Sleep((timeoutWindow + 5) * 1000);
        return Content("This should never get returned, mwahahaaa!");
    }
}
Run Code Online (Sandbox Code Playgroud)

对于我的测试场景,我使用了5秒的配置设置TimeoutFilter,我知道这是有效的,因为当我的测试调用时TimeoutSeconds,我得到正确的值5,但是当测试调用时ForceTimeout,我得到200的HTTP响应和我的'永不返回'文字.

和过滤器:

public class TimeoutFilter : ActionFilterAttribute
{
    internal const string TimeoutSecondsSettingsKey = "MvcActionTimeoutSeconds";
    internal static int TimeoutSeconds;
    public TimeoutFilter()
    {
        TimeoutSeconds = int.Parse(ConfigurationManager.AppSettings[TimeoutSecondsSettingsKey]);
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.Controller.ControllerContext.HttpContext.Server.ScriptTimeout = TimeoutSeconds;
        base.OnActionExecuting(filterContext);
    }
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*ous 13

我不能让这通过设置工作的ScriptTimeout任一属性,设置,即使debug="false"web.config用户埃里克Funkenbusch的建议:

<configuration>
   <system.web>
      <compilation debug="false" targetFramework="4.5"/>
      ...
Run Code Online (Sandbox Code Playgroud)

它继续返回文本"这应该永远不会返回"而不是在期间超时Thread.Sleep.

值得注意的是,我也将其扩展Thread.Sleep到超过Server.ScriptTimeout110秒的默认值,但它最终仍返回相同的文本而不是超时.

然后,我反而试图设置executionTimeoutweb.config:

<configuration>
   <system.web>
      <httpRuntime targetFramework="4.5" executionTimeout="5"/>
      ...
Run Code Online (Sandbox Code Playgroud)

如果您现在要添加一个断点,TimeoutFilter您将观察到该ScriptTimeout值已设置为executionTimeoutweb.config.唉,这对我来说仍然无效(无论是否debug="false").

然后我遇到了这个链接,ScriptTimeoutexecutionTimeout没有使用与你描述的类似的设置.帖子中的第一个回复描述了使用,debug="false"并且还提到超时将延迟5到15秒.即使使用大Thread.Sleep值,我仍然没有运气.本文中的第二个回复表明executionTimeout配置设置是ScriptTimeout属性的替代(显然是经典ASP中使用的COM接口).此回复表明,如果不使用自己的超时逻辑,则无法设置特定的超时.

此外,我接着发现了以下(最近的)链接,其中第一个回复表明在MVC中关闭了超时.进一步的回复表明,这是因为MVCHandler(选择将处理的控制器HTTPRequest)是一个IHttpAsyncHandler因为它可能正在执行另一个请求(这是使用异步请求的点)它因此在内部切换超时状态off(这是我通过阅读此链接收集的内容).它必须直接asp.net使用ScriptTimeout,因为使用似乎是这个答案中可接受的方式.

该链接表明添加以下行将允许它工作(但不在中型信任应用程序中):

System.Web.HttpContext.Current.GetType().GetField("_timeoutState", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(System.Web.HttpContext.Current, 1);
Run Code Online (Sandbox Code Playgroud)

因此,TimeoutFilter OnActionExecuting()改为:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    System.Web.HttpContext.Current.GetType().GetField("_timeoutState", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(System.Web.HttpContext.Current, 1);
    base.OnActionExecuting(filterContext);
}
Run Code Online (Sandbox Code Playgroud)

并设置web.config:

<configuration>
   <system.web>
      <compilation debug="false" targetFramework="4.5"/>
      <httpRuntime targetFramework="4.5" executionTimeout="5"/>
      ...
Run Code Online (Sandbox Code Playgroud)

允许超时工作,但在第一篇文章中提到了轻微的5秒延迟.

注意:使用此方法不允许您ScriptTimeout在过滤器中设置属性.尝试设置ScriptTimeout和覆盖设置的值web.config似乎不起作用.

  • 确实,很好的侦探工作。此外,我发现了这个连接报告,它提出了一种解决方法(不是一个很好的方法,但如果你可以让它工作,它总比没有好)https://connect.microsoft.com/VisualStudio/feedback/details/781171/ asp-net-mvc-executiontimeout-does-not-work (2认同)

Eri*_*sch 9

你在使用调试版本吗?

从ScriptTimeout文档:

http://msdn.microsoft.com/en-us/library/system.web.httpserverutility.scripttimeout(v=vs.110).aspx

如果在Web.config文件中将编译元素的debug属性设置为true,则将忽略ScriptTimeout的值.

此外,由于此值与httpRuntime元素上设置的值相同,我真的不明白这一点,因为您可以在web.config中配置该设置.

编辑:

Dangerous在查找细节方面做得很好,事实上,ScriptTimeout在异步管道中是不受支持的(我认为MVC至少是MVC4,以及WebApi ......即使不使用异步方法)

此连接报告建议的"解决方法":

https://connect.microsoft.com/VisualStudio/feedback/details/781171/asp-net-mvc-executiontimeout-does-not-work

使用该[AsyncTimeout]属性,将取消令牌作为参数,然后CanclationToken.ThrowIfCancelationRequested定期调用,或在异步方法中使用取消令牌.

这是一个例子:

[AsyncTimeout(5000)]
public async Task<ContentResult> Index(CancellationToken ct)
{
    await Task.Delay(10 * 1000, ct);
    return Content("This should never get returned, mwahahaaa!");
}
Run Code Online (Sandbox Code Playgroud)

这会在5秒后以YSOD引发OperationCanceled异常.这样做的好处是它甚至可以在调试模式下工作;)