为什么我的IIS7应用程序池在从ASP.NET页面调用的DLL中发生异常后关闭?

Gor*_*ger 23 iis-7 exception application-pool

我已经阅读了ASP.NET应用程序池关闭问题IIS 7.5的帖子:应用程序池的问题,但他们没有回答我的问题.

我有一个C#ASP.NET页面,在代码隐藏中实例化一个来自通过BIN目录提供的DLL的类,然后在这个实例上调用一个方法.DLL中的方法System.ArgumentException由于DataRow对象中的非现有列而抛出.事件日志显示以下错误:

Source: ASP.NET 2.0.50727.0
Application ID: /LM/W3SVC/1/ROOT/...
Process ID: 9476
Exception: System.ArgumentException
Message: Column 'someColumn' does not belong to table.
StrackTrace: 
Run Code Online (Sandbox Code Playgroud)

ASP.NET页面中的调用代码将方法调用包装在通用try-catch块中.当我请求页面时,这会崩溃我的IIS实例的相应应用程序池,并且我的网站不再可用(错误503).我手动必须重新启动应用程序池,然后该站点再次运行.

根据请求更新try catch ASP.NET代码后面的块:

try
{
    SomeExternalClass someExternalClass = new SomeExternalClass();
    someExternalClass.SomeMethod( someId );
}
catch( Exception ex )
{
    // "smp" is an instance of "StatusMessagePanel", a control we use on all pages 
    // to show error information, basically a div container with an icon.
    smp.ShowError( ex.Message ); 
}
Run Code Online (Sandbox Code Playgroud)

现在我的问题是为什么一个相对"简单"的异常,例如System.ArgumentException在尝试访问非现有DataRow列时被抛出,会导致整个网站崩溃?try-catchASP.NET页面的通用块也没有帮助,这也不是完全使整个网站不可用的原因,还是错误的假设?我从来没有想过这可以基本上把(II)服务器关闭.

期待有人告诉我在访问之前我应该​​检查列的存在:我知道这一点,遗留代码现在已经改变了,但这不是我上面所描述的问题,我想知道为什么后果是如此激烈.

更新2

在DLL内部调用的方法会启动一个包含在try-catch块中的线程:

[...]
try
{
    ThreadStart starter = () => CreateReport(...)
    Thread thread = new Thread( starter );
    thread.Start();
    if( !thread.Join( TimeSpan.FromMinutes( 15 ) ) )
    {
        // Log some timeout warning
    }
    else
    {
        // Log information about successful report generation
    }
}
catch( Exception ex )
{
    // Log error information
}
Run Code Online (Sandbox Code Playgroud)

Zac*_*tes 19

正如您在链接问题中所述,很可能IIS的快速失败保护功能会自动关闭您的应用程序池.如果检查事件日志,则可能会快速连续抛出多个未处理的异常.

简单地说,在可配置的时间范围内有足够的未处理异常(默认值为5分钟内为5)将关闭AppPool,导致503 Service Unavailable响应.

此功能背后的原因是,如果您有一个错误的应用程序,您可能不希望它在每个后续请求中自动重新启动,消耗资源并可能损坏数据.

我必须承认,这不是我所期望的"默认"行为.

查看Rick Stahls的解释,它有点深入.

要真正解决这个问题,您需要捕获异常,或者防止异常被抛出(如@leppie建议的那样).未处理的异常应该拆除整个执行过程(意味着单个请求/工作进程,而不是IIS) - 它使.Net代码更容易调试,因为它不会隐藏错误或只是挂起应用程序.

请注意,这在.Net 2.0中已更改:
http://msdn.microsoft.com/en-us/library/ms228965.aspx
http://support.microsoft.com/kb/911816

更新
根据您的上述更新,我认为您的异常实际上并未被捕获,如果它被抛出CreateReport().该方法在单独的线程上执行:

异常仍然被抛出

CreateReport()如果还没有一个,你需要一个try-catch :

public static void CreateReport() {
    try {
        throw new Exception("reducto");
    } catch {
        Console.WriteLine("done did.");
    }
}
Run Code Online (Sandbox Code Playgroud)