MVC3 中的错误 - 请求永远不会超时。适用于同一项目中的 aspx 页面

发布于 2024-12-01 06:12:42 字数 3444 浏览 0 评论 0 原文

我在我们的生产站点以及我设置的一个小型测试站点上看到了这一点...

基本上,mvc 处理的请求似乎永远不会超时。我在 web.config 中设置了executionTimeout 并关闭了调试模式。然后,我向常规 aspx 页面和 mvc 页面添加了 thread.sleeps 的无限循环(循环位于 mvc 页面的控制器中)。 aspx页面可靠地超时(HttpException(0x80004005):请求超时。),但mvc页面只是永远旋转而不会超时。

mvc 是否有单独的设置(我看过但没有找到)? 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, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
          <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
          <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
          <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, 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>

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've set an executionTimeout in my web.config and turned off debug mode. I've then added an infinite loop of thread.sleeps to both a regular aspx page and an mvc page (the loop is in the controller of the mvc page). The aspx page reliably times out (HttpException (0x80004005): Request timed out.), but the mvc page just spins forever without timing out.

Are there separate settings for mvc (I've looked but haven't found them)? Do mvc requests not timeout by default?

Any help on this would be appreciated. I'll gladly email out my small test site if it would help anyone out.

Edit: I'm using MVC3.

Contents of my 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, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
          <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
          <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
          <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, 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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

蓝海似她心 2024-12-08 06:12:42

我认为,我找到了原因:

此方法位于 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, 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);
    }
}

编辑:想出了一种笨拙的方法来强制 MVC 控制器操作“时间” out”,虽然这个机制有点野蛮:

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

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

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;                    
            }
        }
    }
}
浊酒尽余欢 2024-12-08 06:12:42

当满足以下条件时,它应该可以工作:

1)域名不是本地主机(要测试超时,您应该使用“YourComputerName”而不是“localhost”)。

2)项目以Release模式编译。

3) 编译 debug="false"

如果没有,请在此处寻找替代方案 (ScriptTimeOut):
ASP.NET MVC 和 httpRuntimeexecutionTimeout

您好,
爸爸

It should work when these conditions are met:

1) Domain name is not localhost (to test timeout you should use "YourComputerName" instead of "localhost").

2) Project is compiled in Release mode.

3) compilation debug="false"

if not look here for an alternative (ScriptTimeOut):
ASP.NET MVC and httpRuntime executionTimeout

Greetings,
Daddy

眼眸里的快感 2024-12-08 06:12:42

在 MVC 4 中仍然发生在我身上。我已将其作为错误提交给微软:

https://connect.microsoft.com/VisualStudio/feedback/details/781171/asp-net-mvc-executiontimeout-does-not-work

更新:

微软评论如下:

MVC中不建议使用执行超时功能
应用程序。您可以将 HttpContext.Server.ScriptTimeout 设置为
所需的超时值。尽管有这个名字,但这是一个按请求
设置并应适用于任何 ASP.NET 请求(名称“脚本”是
误导)

Still happening for me in MVC 4. I have submitted this to microsoft as a bug:

https://connect.microsoft.com/VisualStudio/feedback/details/781171/asp-net-mvc-executiontimeout-does-not-work

Update:

Microsoft commented with the following:

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)

.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文