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

时间:2014-11-27 11:55:02

标签: asp.net-mvc asp.net-mvc-4 http

我有以下控制器:

[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!");
    }
}

对于我的测试场景,我在TimeoutFilter中使用了5秒的配置设置,我知道这是有效的,因为当我的测试调用TimeoutSeconds时,我得到正确的值5,但是当测试调用ForceTimeout,我的HTTP响应为200,而我的回复从未返回过{&1;}。文本。

过滤器:

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);
    }
}

2 个答案:

答案 0 :(得分:11)

即使按照用户Erik Funkenbusch建议的ScriptTimeout设置debug="false",我也无法通过设置web.config属性来实现此功能:

<configuration>
   <system.web>
      <compilation debug="false" targetFramework="4.5"/>
      ...

它继续返回“永远不会返回”的文字,而不是在Thread.Sleep期间超时。

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

然后我尝试在executionTimeout

中设置web.config
<configuration>
   <system.web>
      <httpRuntime targetFramework="4.5" executionTimeout="5"/>
      ...

如果您现在要向TimeoutFilter添加断点,您会发现ScriptTimeout值已设置为executionTimeout的{​​{1}}值。唉,这对我来说仍然无效(无论是web.config)。

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

此外,我接着遇到了following (more recent) link,其中第一个回复表明在MVC中关闭了超时。进一步的回复表明这是因为MVCHandler(选择将处理ScriptTimeout的控制器)是HTTPRequest因为它可能正在执行另一个请求(这是重点)因此,它在内部切换超时状态(这是我从阅读此链接收集的内容)。它必须与IHttpAsyncHandler一起使用,但使用asp.net似乎是this answer中可接受的方式。

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

ScriptTimeout

因此,请将System.Web.HttpContext.Current.GetType().GetField("_timeoutState", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).SetValue(System.Web.HttpContext.Current, 1); 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); }

web.config

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

注意:使用此方法不允许您在过滤器中设置<configuration> <system.web> <compilation debug="false" targetFramework="4.5"/> <httpRuntime targetFramework="4.5" executionTimeout="5"/> ... 属性。尝试设置ScriptTimeout并覆盖ScriptTimeout中设置的值似乎不起作用。

答案 1 :(得分:9)

您使用的是调试版本吗?

从ScriptTimeout文档:

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

  

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

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

编辑:

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

&#34;解决方法&#34;正如此连接报告所建议的那样:

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!");
}

这会在5秒后抛出一个带有YSOD的OperationCanceled异常。这样做的好处是它甚至可以在调试模式下工作;)