24

我已阅读帖子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: 

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

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

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

现在我的问题是,为什么一个相对“简单”的异常(例如System.ArgumentException在尝试访问不存在的DataRow列时抛出)会使整个网站崩溃?ASP.NET 页面的通用try-catch块也没有帮助,这也不应该是使整个网站完全不可用的原因,或者这是一个错误的假设?我从没想过这基本上可以使(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
}
4

2 回答 2

20

正如您在链接问题中所指出的那样,您的应用程序池很可能会被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(). 该方法在单独的线程上执行:

仍然抛出异常

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

public static void CreateReport() {
    try {
        throw new Exception("reducto");
    } catch {
        Console.WriteLine("done did.");
    }
}
于 2013-04-23T07:27:00.030 回答
4

它发生在我身上一次。真正的错误(在我的情况下)是关闭池的堆栈溢出。

似乎 IIS 正在保护自己免于消耗过多的资源。

我使用 DebugDiag 发现了问题。

这是我开始的地方:http ://www.webdebug.ne​​t/index.php/2012/12/collect-iis-crash-dump-with-debugdiag/

我想了解为什么外部 DLL 中的异常会导致 IIS 应用程序池关闭,即使异常在 DLL 中被捕获,并且在从 ASP.NET 页面后面的代码中调用 DLL 的方法时也是如此.

外部 dll 也在您的应用程序池中运行。此 dll 中的重大崩溃也会使您的应用程序池崩溃。有些异常无法处理,stackoverflow 异常就是其中之一。这里讨论主题。也许这就是你的情况。

于 2013-04-16T18:47:29.967 回答