我在我们的生产网站上看到这个,以及一个小的测试网站,我只是为了测试这个…
基本上,似乎由mvc处理的请求永远不会超时。我在我的web.config中设置了一个executionTimeout并关闭调试模式。然后我添加了一个无限循环的thread.sleeps到一个常规aspx页面和一个mvc页面(循环是在mvc页面的控制器)。 aspx页面可靠超时(HttpException(0x80004005):请求超时。),但是mvc页面只是旋转永远没有超时。
有没有单独的设置mvc(我看过,但没有找到它们)? Do mvc请求默认不超时?
任何帮助,这将不胜感激。我会很高兴地发电子邮件发送我的小测试网站,如果它会帮助任何人。
编辑:我使用MVC3。
我的web.config的内容:
<?xml version="1.0"?> <!-- For more information on how to configure your ASP.NET application,please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <connectionStrings> <add name="ApplicationServices" connectionString="data source=.\sqlEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true" providerName="System.Data.sqlClient" /> </connectionStrings> <appSettings> <add key="webpages:Enabled" value="true" /> </appSettings> <system.web> <httpRuntime maxRequestLength="16384" executionTimeout="30" /> <compilation debug="false" targetFramework="4.0"> <assemblies> <add assembly="System.Web.Abstractions,Version=4.0.0.0,Culture=neutral,PublicKeyToken=31BF3856AD364E35" /> <add assembly="System.Web.Helpers,Version=1.0.0.0,PublicKeyToken=31BF3856AD364E35" /> <add assembly="System.Web.Routing,PublicKeyToken=31BF3856AD364E35" /> <add assembly="System.Web.Mvc,Version=3.0.0.0,PublicKeyToken=31BF3856AD364E35" /> <add assembly="System.Web.WebPages,PublicKeyToken=31BF3856AD364E35" /> </assemblies> </compilation> <authentication mode="Forms"> <forms loginUrl="~/Account/Login.aspx" timeout="2880" /> </authentication> <membership> <providers> <clear/> <add name="AspNetsqlMembershipProvider" type="System.Web.Security.sqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minrequiredPasswordLength="6" minrequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" /> </providers> </membership> <profile> <providers> <clear/> <add name="AspNetsqlProfileProvider" type="System.Web.Profile.sqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/> </providers> </profile> <roleManager enabled="false"> <providers> <clear/> <add name="AspNetsqlRoleProvider" type="System.Web.Security.sqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" /> <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" /> </providers> </roleManager> </system.web> <system.webServer> <modules runAllManagedModulesForAllRequests="true"/> </system.webServer> </configuration>
解决方法
我找到了这个的原因,methinks:
此方法在WrappedAsyncResult类中,MvcHandler类通过BeginProcessRequest使用该类:
public static IAsyncResult BeginSynchronous<TResult>(AsyncCallback callback,object state,Func<TResult> func,object tag) { BeginInvokeDelegate beginDelegate = delegate (AsyncCallback asyncCallback,object asyncState) { SimpleAsyncResult result = new SimpleAsyncResult(asyncState); result.MarkCompleted(true,asyncCallback); return result; }; EndInvokeDelegate<TResult> endDelegate = _ => func(); WrappedAsyncResult<TResult> result = new WrappedAsyncResult<TResult>(beginDelegate,endDelegate,tag); result.Begin(callback,state,-1); return result; }
其中“Begin”是:
public void Begin(AsyncCallback callback,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); } }
编辑:提出了一个ham-handed的方式强制MVC控制器的行动“超时”,虽然机制有点粗暴:
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; } } } }