I\'m seeing this on our production site as well as a small test site I setup just to test this out...
Basically, it appears that requests handled by mvc never time out.
I found the cause for this, methinks:
This method is in the WrappedAsyncResult class, which the MvcHandler class uses via BeginProcessRequest:
public static IAsyncResult BeginSynchronous(AsyncCallback callback, object state, Func func, object tag)
{
BeginInvokeDelegate beginDelegate = delegate (AsyncCallback asyncCallback, object asyncState) {
SimpleAsyncResult result = new SimpleAsyncResult(asyncState);
result.MarkCompleted(true, asyncCallback);
return result;
};
EndInvokeDelegate endDelegate = _ => func();
WrappedAsyncResult result = new WrappedAsyncResult(beginDelegate, endDelegate, tag);
result.Begin(callback, state, -1);
return result;
}
where "Begin" is:
public void Begin(AsyncCallback callback, object state, int timeout)
{
bool completedSynchronously;
this._originalCallback = callback;
lock (this._beginDelegateLockObj)
{
this._innerAsyncResult = this._beginDelegate(new AsyncCallback(this.HandleAsynchronousCompletion), state);
completedSynchronously = this._innerAsyncResult.CompletedSynchronously;
if (!completedSynchronously && (timeout > -1))
{
this.CreateTimer(timeout);
}
}
if (completedSynchronously && (callback != null))
{
callback(this);
}
}
EDIT: have come up with a ham-handed way of forcing MVC controller actions to "time out", although the mechanism is a bit brutish:
public class TimeoutController : Controller
{
private bool _isExecuting = false;
private int _controllerTimeout = 5000;
private Thread _executingThread;
private readonly object _syncRoot = new object();
protected override void ExecuteCore()
{
_executingThread = Thread.CurrentThread;
ThreadPool.QueueUserWorkItem(o =>
{
Thread.Sleep(_controllerTimeout);
if (_isExecuting)
{
_executingThread.Abort();
}
});
base.ExecuteCore();
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
_isExecuting = true;
base.OnActionExecuting(filterContext);
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
_isExecuting = false;
base.OnActionExecuted(filterContext);
}
public int ControllerTimeout
{
get
{
int retVal;
lock(_syncRoot)
{
retVal = _controllerTimeout;
}
return retVal;
}
set
{
lock(_syncRoot)
{
_controllerTimeout = value;
}
}
}
}