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);
}
}
I could not get this to work by setting the
ScriptTimeout
property either, even when setting thedebug="false"
in theweb.config
as suggested by user Erik Funkenbusch: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 theServer.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 theweb.config
:If you were to now add a breakpoint to the
TimeoutFilter
you will observe that theScriptTimeout
value has been set to theexecutionTimeout
value fromweb.config
. Alas, this still did not work for me (regardless of whetherdebug="false"
).I then came across this link about
ScriptTimeout
andexecutionTimeout
not working with a similar setup to what you describe. The first reply in the post describes using thedebug="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 largeThread.Sleep
value. The second reply in this article suggests that theexecutionTimeout
config setting is a replacement of theScriptTimeout
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 theHTTPRequest
) is anIHttpAsyncHandler
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 straightasp.net
though as usingScriptTimeout
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):
Therefore, changing the
TimeoutFilter
OnActionExecuting()
to:and setting the
web.config
: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 setScriptTimeout
and override the value set inweb.config
does not appear to work.Are you using a debug build?From the ScriptTimeout documentation:
http://msdn.microsoft.com/en-us/library/system.web.httpserverutility.scripttimeout(v=vs.110).aspx
Also, since this value is the same as that set on the httpRuntime element, I really don't understand the point of this, since you can just configure that setting in in your web.config instead.
Edit:
Dangerous has done a good job of finding out the details, and indeed, ScriptTimeout is unsupported in asynchronous pipelines (which MVC has been since at least MVC4 I think, as well as WebApi.. even if not using async methods)
The "workaround" as suggested by this connect report:
https://connect.microsoft.com/VisualStudio/feedback/details/781171/asp-net-mvc-executiontimeout-does-not-work
Use the
[AsyncTimeout]
attribute, and take a cancelation token as a parameter, then callCanclationToken.ThrowIfCancelationRequested
periodically, or use the cancellation token in an async method.Here's an example:
This throws an OperationCanceled exception with a YSOD after 5 seconds. The bonus for this is that it works even in Debug mode ;)