捕获 IIS 级未处理的异常

Posted

技术标签:

【中文标题】捕获 IIS 级未处理的异常【英文标题】:Catching IIS-level unhandled exceptions 【发布时间】:2020-08-14 11:50:30 【问题描述】:

我正在尝试在我们的一个 ASP.NET Web API(非核心)项目(运行 .NET 4.7.2)上实现错误处理,以避免将来遇到错误,我们有几天前。

错误是Web.Config文件中的这段代码没有更新,但是项目发布时自带的DLL更新了,所以版本不匹配。

  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs"
        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701"/>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
        warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
    </compilers>
  </system.codedom>

compiler 两行中的Version=2.0.1.0 均设置为Version=1.0.8.0,并且发布的 DLL 版本为 2.0.1.0。这给出了一个看起来像这样的错误:

现在,我想在代码中处理这个异常,并将其记录到我们的日志堆栈中。我四处搜索并发现了几种在 web.api 项目中捕获异常的不同方法,但它们似乎都没有奏效。我试过的有:

global.asax.cs 文件中:

        void Application_Error(object sender, EventArgs e)
        
            Exception ex = Server.GetLastError();

            if (ex != null)
                Logger.WriteToFile(ex.Message, ex);
        

也在global.asax.cs 文件中:

        protected void Application_Start()
        
            GlobalConfiguration.Configure(WebApiConfig.Register);

            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        

        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        
            Exception ex = (e.ExceptionObject as Exception);

            if (ex != null) 
                Logger.WriteToFile(ex.Message, ex);
        

在自动添加到 Web.API 的 WebApiConfig.Register 函数中(例如,处理路由设置):

        public static void Register(HttpConfiguration config)
        
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Filters.Add(new GlobalExceptionFilterAttribute()); // <-- this line

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/controller/id",
                defaults: new  id = RouteParameter.Optional 
            );
        

    public class GlobalExceptionFilterAttribute : ExceptionFilterAttribute
    
        public override void OnException(HttpActionExecutedContext context)
        
            var exceptionType = context.Exception.GetType().ToString();
            var exception = context.Exception.InnerException ?? context.Exception;

            try
            
                if (exception != null)
                    Logger.WriteToFile(exception.Message, exception);
            
            finally
            
                base.OnException(context);
            
        
    

在 web.config 文件中,我添加了一个应该(理论上)处理 IIS 级别错误的模块(取自 Catch IIS level error to handle in ASP.NET):

  <system.webServer>
    <modules>
      <add type="ErrorHttpModule" name="ErrorHttpModule"/>
    </modules>
  </system.webServer>
public class ErrorHttpModule : IHttpModule

    private HttpApplication _context;

    public ErrorHttpModule()  

    public void Init(HttpApplication context)
    
        _context = context;
        _context.Error += new EventHandler(ErrorHandler);
    

    private void ErrorHandler(object sender, EventArgs e)
    
        Exception ex = _context.Server.GetLastError();

        if (ex != null)
            Logger.WriteToFile(ex.Message, ex);
    

    public void Dispose()
    
    

而且这些似乎都没有捕获错误并记录它。我如何捕捉到这个错误?

除了我们的主项目之外,我还在一个完全空白的 Web.API 项目中重现了这个错误。空白 Web.API 项目可以在 https://github.com/Loyalar/IISExceptionCapture 找到。

【问题讨论】:

【参考方案1】:

疑难解答:

    启用 stdoutLogEnabled 并检查 IIS 日志。

    您还可以查看窗口日志事件。

参考 - https://weblog.west-wind.com/posts/2020/Jan/14/ASPNET-Core-IIS-InProcess-Hosting-Issues-in-NET-Core-31

【讨论】:

看起来 stdoutLogEnabled 是 .NET 核心项目的功能。这是一个 .NET Framework 项目,很遗憾,不能使用 .NET core 的日志记录功能。【参考方案2】:

您可以在应用程序开始时使用以下代码。在 Program.cs、Startup.cs 或您的 Global.asax 文件中。

AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>

    Debug.WriteLine(eventArgs.Exception.ToString());
;

更多详情请参考以下链接:

https://stackify.com/csharp-catch-all-exceptions/

catch all unhandled exceptions in ASP.NET Web Api

【讨论】:

要注册FirstChanceExceptions,仍然需要应用程序来运行Global.asax.cs 文件中的代码,不幸的是,在我的情况下不需要。它永远不会到达global.asax.cs 代码。 Startup.cs 文件(正如我所读)仅适用于 ASP.NET Core 项目,不幸的是我的项目不是。 Stackify 链接通过这些相同的解决方案 - 无济于事。不幸的是,您发送的另一个链接中的ExceptionLogger“解决方案”在生命周期的同一点注册-永远无法达到的WebApiConfig.Register函数。

以上是关于捕获 IIS 级未处理的异常的主要内容,如果未能解决你的问题,请参考以下文章

PHP 异常处理 总出现致命错误 无法捕获异常

新人求教,请问Thinkphp 中怎么捕获异常,自己进行处理

Java中的异常的捕获和抛出是啥意思,有啥区别

iOS异常信号的捕获和简单处理

Kotlin空安全 ⑤ ( 异常处理 | 捕获并处理异常 | 抛出自定义异常 )

异常的捕获和处理