为啥我的 IIS7 应用程序池在从 ASP.NET 页面调用的 DLL 中出现异常后关闭?

Posted

技术标签:

【中文标题】为啥我的 IIS7 应用程序池在从 ASP.NET 页面调用的 DLL 中出现异常后关闭?【英文标题】:Why does my IIS7 application pool shutdown after an exception in a DLL called from an ASP.NET page?为什么我的 IIS7 应用程序池在从 ASP.NET 页面调用的 DLL 中出现异常后关闭? 【发布时间】:2013-04-05 05:02:58 【问题描述】:

我已经阅读了ASP.NET application pool shutdown problem 和IIS 7.5: problem with Application pool 的帖子,但他们没有回答我的问题。

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

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

现在我的问题是,为什么在尝试访问不存在的DataRow 列时抛出一个相对“简单”的异常(例如System.ArgumentException)会导致整个网站崩溃? 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

【问题讨论】:

catch 块中发生了什么?如果这引发异常,您可能会遇到麻烦。可以贴一下try catch代码吗? catch 块调用的方法只是使错误消息对客户端(浏览器)可见,我将更新我的问题。 开个玩笑——如果你完全删除 try-catch 块并调用该方法,应用程序池是否仍然崩溃? 回到工作岗位时试试:-) 和以前一样。删除 ASP.NET 页面背后代码的异常处理会导致应用程序池关闭。 【参考方案1】:

正如您在链接问题中所指出的,您的应用程序池很可能会被 IIS's Rapid Fail Protection 功能自动关闭。如果您检查事件日志,可能会快速连续抛出多个未处理的异常。

简单地说,在可配置的时间跨度内(默认为 5 分钟内 5 次)有足够多的未处理异常将关闭 AppPool,从而导致 503 Service Unavailable 响应。

此功能背后的原因是,如果您的应用程序有问题,您可能不希望它在每次后续请求时自动重新启动,从而消耗资源并可能损坏数据。

我不得不承认这也不是我所期望的“默认”行为。

查看Rick Stahls explanation,它更深入一点。

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

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

更新 根据您上面的更新,我认为您的异常实际上不会被捕获,如果它是从CreateReport() 抛出的。该方法在单独的线程上执行:

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

public static void CreateReport() 
    try 
        throw new Exception("reducto");
     catch 
        Console.WriteLine("done did.");
    

【讨论】:

感谢您提供更详细的信息,尽管我仍然不明白为什么在 DLL 中捕获的异常会导致应用程序池关闭。快速连续抛出的多个异常也不应该是这种情况,因为 DLL 方法的执行会随着第一个异常被抛出而终止。事件日志还显示只生成了一个异常。 谢谢,我会尽快找到时间进行验证 - 我们刚刚将 TFS 移到了不同​​的网络,并且仍在重新加快速度,非常抱歉对于延迟,请耐心等待几天。 就是这样,确实有点隐蔽。该方法中有一个 try catch 块,但它只捕获了一种(不同的)异常,当我遇到问题中描述的问题时,这种异常没有发生。再次感谢:-)【参考方案2】:

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

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

我使用 DebugDiag 发现了问题。

我从这里开始:http://www.webdebug.net/index.php/2012/12/collect-iis-crash-dump-with-debugdiag/

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

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

【讨论】:

以上是关于为啥我的 IIS7 应用程序池在从 ASP.NET 页面调用的 DLL 中出现异常后关闭?的主要内容,如果未能解决你的问题,请参考以下文章

用户 ASP.NET 运行在

我需要更改啥以允许我的 IIS7 ASP.Net 3.5 应用程序创建事件源并将事件记录到 Windows EventLog?

在 IIS7 中托管 ASP.NET 会导致访问被拒绝?

ASP.NET 输出缓存在 IIS7.5 上不起作用

无法让 ELMAH 在 IIS7.5 上与 ASP.NET MVC2 一起使用

如何将 ASP.NET 2.0 注册到 Web 服务器(IIS7)?