Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
507 views
in Technique[技术] by (71.8m points)

asp.net mvc - Why doesn't my action method time out?

I have the following controllers:

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

For my test scenario I use a config setting of 5 seconds in the TimeoutFilter, and I know this is working because when my test calls TimeoutSeconds, I get the correct value of 5, but when the test calls ForceTimeout, I get an HTTP response of 200 and my 'never returned' text.

And the filter:

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);
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I could not get this to work by setting the ScriptTimeout property either, even when setting the debug="false" in the web.config as suggested by user Erik Funkenbusch:

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

It continued to return the text "This should never get returned" rather than timing out during the Thread.Sleep.

It is also worth noting that I also extended the Thread.Sleep to well beyond the Server.ScriptTimeout default of 110 seconds but it still eventually returned the same text rather than timing out.

I then instead tried to set executionTimeout in the web.config:

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

If you were to now add a breakpoint to the TimeoutFilter you will observe that the ScriptTimeout value has been set to the executionTimeout value from web.config. Alas, this still did not work for me (regardless of whether debug="false").

I then came across this link about ScriptTimeout and executionTimeout not working with a similar setup to what you describe. The first reply in the post describes using the debug="false" and also mentions that the timeout will have a delay of 5 to 15 seconds. I still had no luck even when using a large Thread.Sleep value. The second reply in this article suggests that the executionTimeout config setting is a replacement of the ScriptTimeout property (which is apparently a COM interface used in classic ASP). This reply suggests that is not possible to set a specific timeout without using your own time-out logic.

Further, I then came across the following (more recent) link where the first reply suggests that the timeout is switched off in MVC. A further reply suggests that this is because an MVCHandler (which selects the controller that will handle the HTTPRequest) is an IHttpAsyncHandler and as it may therefore be executing another request (which is the point of using an async request) it therefore internally switches the time-out state off (this is what I gather from reading this link). It must work with straight asp.net though as using ScriptTimeout seems to be the accepted way in this answer.

The link suggests that adding the following line will allow it to work (but not in a medium trust application):

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

Therefore, changing the TimeoutFilter OnActionExecuting() to:

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

and setting the web.config:

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

allows the time-out to work but has the slight 5 second delay that is mentioned in the first post.

Note: Using this method does not allow you to set the ScriptTimeout property in the filter. Trying to set ScriptTimeout and override the value set in web.config does not appear to work.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...