我有一个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 }
解决方法
简单地说,在可配置的时间范围内(默认为5分钟5分钟)中的足够的未处理的异常将关闭AppPool,导致503 Service Unavailable响应。
此功能背后的原因是,如果您的应用程序有问题,您可能不希望在每个后续请求中自动重新启动它,从而消耗资源并可能损坏数据。
我不得不承认,这不是我预期的“默认”行为。
查看Rick Stahls explanation,这有点更深入。
要真正解决这个问题,您需要捕获异常,或者阻止异常抛出(像@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."); } }