【问题标题】:Why doesn't my action method time out?为什么我的操作方法没有超时?
【发布时间】:2015-01-26 00:29:38
【问题描述】:

我有以下控制器:

[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,但是当测试调用 @ 987654324@,我收到 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);
    }
}

【问题讨论】:

  • 你能提供你的超时过滤器实现吗?
  • @JalpeshVadgama 已按要求添加。

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


【解决方案1】:

您使用的是调试版本吗?

来自 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(我认为至少从 MVC4 开始,以及 WebApi..,即使不使用异步方法,也支持 MVC)

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

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 异常。这样做的好处是它甚至可以在调试模式下工作;)

【讨论】:

  • 我不确定最终的配置值是什么,在阅读了一些关于 machine.config 覆盖该值的信息后,“机器”是一个 Azure 网站。这样我就可以坚持一定的超时值。
  • @ProfK - 当我给你答案时,你为什么要发布赏金?
  • Erik,正如上面 Dangerous 所指出的,更改“调试”属性本身没有任何效果。
  • @ProfK - 好吧,你没有提到你甚至尝试过,更不用说它不起作用了。如果人们发布答案时,您可以向他们更新答案是否有效,这可能会有所帮助。
  • 该链接是一个很好的发现,因为这方面的文档似乎很少。与使用反射(在我的回答中建议)相比,[AsyncTimeout] 方法确实有效且准确,并且确实具有在调试中工作的额外好处。
【解决方案2】:

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

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

Thread.Sleep 期间它继续返回文本“这永远不会被返回”而不是超时。

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

然后我尝试在web.config 中设置executionTimeout

<configuration>
   <system.web>
      <httpRuntime targetFramework="4.5" executionTimeout="5"/>
      ...

如果您现在要向TimeoutFilter 添加断点,您会发现ScriptTimeout 的值已从web.config 设置为executionTimeout 值。唉,这对我仍然不起作用(不管 debug="false" 是否)。

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

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

该链接建议添加以下行将允许它工作(但不能在中等信任应用程序中):

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:

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

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

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-03
  • 1970-01-01
  • 2015-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多