Home Dashboard Directory Help
Search

ASP.NET MVC ExecutionTimeout does not work by manchesterUnited08


Status: 

Active


10
0
Sign in
to vote
Type: Bug
ID: 781171
Opened: 3/11/2013 8:21:15 PM
Access Restriction: Public
2
Workaround(s)
view
2
User(s) can reproduce this bug

Description

Using ASP.NET MVC 3 & 4, I cannot get the ExecutionTimeout to work. I have tried running a simple application, hosted on a remote server, built using release mode, with the following in the web.config:

     <httpRuntime maxRequestLength="16384" executionTimeout="30" />

I added a simple controller method that spins for half an hour. The request runs and completes after half an hour. IIS never shuts down the request, even though I have the execution timeout set. I am not the only person seeing this behavior:

http://stackoverflow.com/questions/7198267/bug-in-mvc3-requests-never-time-out-works-fine-for-aspx-pages-in-same-projec
http://stackoverflow.com/questions/11657381/net-execution-timeout-not-taking-effect-in-an-mvc-web-project
Details
Sign in to post a comment.
Posted by Microsoft on 7/31/2013 at 6:22 PM
Apparently I was mistaken in my previous comment about execution timeouts. I have consulted with another person on the team and this is their statement recarding timeouts:

ExecutionTimeout / ScriptTimeout only apply to synchronous handlers in ASP.NET. Both MVC and Web API are completely asynchronous (even if you're not using async controllers) pipelines, so ExecutionTimeout / ScriptTimeout have no effect.

If you want to timeout MVC requests, consider using the [AsyncTimeout] attribute and taking a CancellationToken as a parameter to your action method (which will be automatically populated). You can monitor this CancellationToken and time out your operation as appropriate. For example, if you have a synchronous controller and are doing CPU-bound work, you could poll the CancellationToken every so often. Or if you have an asynchronous controller and are doing IO-bound work, you could supply a callback for it to invoke when the timeout occurs.

Thanks,
The ASP.NET Team
Posted by Microsoft on 7/22/2013 at 4:04 PM
Hi folks,

The execution timeout feature is not advised to be used in MVC applications. You can instead set HttpContext.Server.ScriptTimeout to the desired timeout value. Despite the name, this is a per-request setting and should apply to any ASP.NET request (the name "script" is misleading).

Thanks,
The ASP.NET Team
Posted by Microsoft on 7/22/2013 at 4:04 PM
Hi folks,

The execution timeout feature is not advised to be used in MVC applications. You can instead set HttpContext.Server.ScriptTimeout to the desired timeout value. Despite the name, this is a per-request setting and should apply to any ASP.NET request (the name "script" is misleading).

Thanks,
The ASP.NET Team
Posted by Microsoft on 3/19/2013 at 2:27 AM
Thank you for submitting feedback on Visual Studio and .NET Framework. Your issue has been routed to the appropriate VS development team for investigation. We will contact you if we require any additional information.
Posted by Microsoft on 3/12/2013 at 10:42 PM
Thank you for your feedback, we are currently reviewing the issue you have submitted. If this issue is urgent, please contact support directly(http://support.microsoft.com)
Sign in to post a workaround.
Posted by manchesterUnited08 on 3/19/2013 at 8:02 AM
Sorry, that wasn't readable. Here's a Gist that's a bit better:
https://gist.github.com/reustmd/5196853
Posted by manchesterUnited08 on 3/19/2013 at 8:01 AM
We wrote an ActionFilter that hits private members in .NET to trigger the timeout functionality.

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
    internal sealed class ExecutionTimeoutToGetAroundBugInMVC3Attribute : ActionFilterAttribute
    {
        public ExecutionTimeoutToGetAroundBugInMVC3Attribute() { }
        private MethodInfo _beginMethod;
        private MethodInfo _endMethod;

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            try
            {
                var context = HttpContext.Current;

                if (_beginMethod == null) //thread locking is known to loose here since it only affects app start up.
                    _beginMethod = context.GetType().GetMethod("BeginCancellablePeriod", BindingFlags.NonPublic | BindingFlags.Instance);

                _beginMethod.Invoke(context, null);
            }
            catch (Exception ex)
            {
                GroupCommerce.Logging.LoggerPlaceHolder.RealIfExistsOrFakeLogger.Error("Could not call BeginCancellablePeriod() on http context.", ex);
            }

        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            try
            {
                var context = HttpContext.Current;

                if (_endMethod == null) //thread locking is known to loose here since it only affects app start up.
                    _endMethod = context.GetType().GetMethod("EndCancellablePeriod", BindingFlags.NonPublic | BindingFlags.Instance);

                _endMethod.Invoke(context, null);
            }
            catch (Exception ex)
            {
                GroupCommerce.Logging.LoggerPlaceHolder.RealIfExistsOrFakeLogger.Error("Could not call EndCancellablePeriod() on http context.", ex);
            }
        }
    }