【问题标题】:Application_Error in global.asax not catching errors in WebAPIglobal.asax 中的 Application_Error 未捕获 WebAPI 中的错误
【发布时间】:2015-04-30 09:07:34
【问题描述】:

对于我正在处理的项目,我们正在实施的其中一件事是我们在我的一些团队中为一些较旧的 ASP.NET 和 MVC 项目提供了代码 - 一个 Application_Error 异常捕获器,可将电子邮件发送到具有异常经验和最相关细节的开发团队。

它的外观如下:

Global.asax:

protected void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();
    string path = "N/A";
    if (sender is HttpApplication)
        path = ((HttpApplication) sender).Request.Url.PathAndQuery;

    string args = string.Format("<b>Path:</b> {0}", path);

    // Custom code that generates an HTML-formatted exception dump
    string message = Email.GenerateExceptionMessage(ex, args);

    // Custom code that sends an email to the dev team.
    Email.SendUnexpectedErrorMessage("Some App", message);
}

不过,有一个“小”问题 - 当我故意让一部分代码抛出异常以测试此机制时...

public static void GetMuffinsByTopping(string topping)
{
    throw new Exception("Test Exception!", new Exception("Test Inner Exception!!!"));

    // Actual repository code is unreachable while this test code is there
}

前端 JavaScript 正在立即拦截 HTTP 500 请求,但没有到达上面提到的 global.asax.cs 代码(我在方法的第一行设置了断点。)

问题:我可以通过什么方式让“旧”Application_Error 处理程序发送错误电子邮件,以便我们团队的开发人员可以更轻松地调试我们的应用程序?

【问题讨论】:

  • 您可以将错误处理逻辑抽象为Application_Error 调用的单独方法,将Web API 方法主体包装在try/catch 中,然后手动将错误逻辑从Web API 传递给抽象方法错误。我敢肯定,这不是最干净的方式,但它应该很容易实现并且“正常工作”。对于更清洁的方法,您可以查看Exception Handling in ASP.NET Web API
  • 我同意这是一个很好的“让它工作”的建议。我问这个的原因是,根据我的技术主管的指导,在每个 API 方法中都有一个try/catch 实际上是我想要摆脱的。不过,如果所有其他方法都失败了,我们的团队可以将其用作后备。这将是一个非常令人讨厌的模式。
  • 我编辑了我的最后一条评论。查看我提供的链接,并查看异常过滤器。这看起来是一种避免在所有 Web API 方法体中使用 try/catch 的好方法。
  • 这对我来说很有效。您是否介意回答您的评论,即使用异常过滤器是一种更好的方法?

标签: c# asp.net .net asp.net-web-api error-reporting


【解决方案1】:

将您的错误处理逻辑从Application_Error 抽象到它自己的函数中。创建一个Web API exception filter

//register your filter with Web API pipeline
//this belongs in the Application_Start event in Global Application Handler class (global.asax)
//or some other location that runs on startup
GlobalConfiguration.Configuration.Filters.Add(new LogExceptionFilterAttribute());

//Create filter
public class LogExceptionFilterAttribute : ExceptionFilterAttribute 
{
    public override void OnException(HttpActionExecutedContext context)
    {
        ErrorLogService.LogError(context.Exception);
    }
}

//in global.asax or global.asax.cs
protected void Application_Error(object sender, EventArgs e)
{
    Exception ex = Server.GetLastError();
    ErrorLogService.LogError(ex);
} 

//common service to be used for logging errors
public static class ErrorLogService
{
    public static void LogError(Exception ex)
    {
        //Email developers, call fire department, log to database etc.
    }
}

来自 Web API 的错误不会触发 Application_Error 事件。但是我们可以创建一个异常过滤器并注册它来处理错误。另见Global Error Handling in ASP.NET Web API 2

【讨论】:

  • 为什么?我不明白。这是最好的做法?
  • @LeandroDeMelloFagundes Web API 出现异常时不会触发 Application_Error 事件。您可能已经登录 Application_Error 来处理 ASP.NET 异常。因此,将该逻辑放在一个公共服务中,该服务可以从 Application_Error 或应用于 Web API 操作方法的异常过滤器中使用,遵循 DRY 原则。没有重复的逻辑。
  • 感谢@mason,从 asp.net 网站阅读您的答案中的链接也有助于了解发生的情况。很好的回答
  • 你应该把这条线放在哪里: GlobalConfiguration.Configuration.Filters.Add(new LogExceptionFilterAttribute());是在 global.asax Application_Start() 还是 Application_Error() 中?
  • @Paul 它应该在Application_Start 中,因为您正在注册过滤器,以便它知道在错误发生时如何处理错误。您总是在应用程序启动时注册任何过滤器。
【解决方案2】:

就我而言,我不喜欢使用 Web.config。然后我在 Global.asax 文件中创建了上面的代码:

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

        //Not Found (When user digit unexisting url)
        if(ex is HttpException && ((HttpException)ex).GetHttpCode() == 404)
        {
            HttpContextWrapper contextWrapper = new HttpContextWrapper(this.Context);

            RouteData routeData = new RouteData();
            routeData.Values.Add("controller", "Error");
            routeData.Values.Add("action", "NotFound");

            IController controller = new ErrorController();
            RequestContext requestContext = new RequestContext(contextWrapper, routeData);
            controller.Execute(requestContext);
            Response.End();
        }
        else //Unhandled Errors from aplication
        {
            ErrorLogService.LogError(ex);
            HttpContextWrapper contextWrapper = new HttpContextWrapper(this.Context);

            RouteData routeData = new RouteData();
            routeData.Values.Add("controller", "Error");
            routeData.Values.Add("action", "Index");

            IController controller = new ErrorController();
            RequestContext requestContext = new RequestContext(contextWrapper, routeData);
            controller.Execute(requestContext);
            Response.End();
        }
    }

这就是我的 ErrorController.cs

public class ErrorController : Controller
{
    // GET: Error
    public ViewResult Index()
    {
        Response.StatusCode = 500;
        Exception ex = Server.GetLastError();
        return View("~/Views/Shared/SAAS/Error.cshtml", ex);
    }

    public ViewResult NotFound()
    {
        Response.StatusCode = 404;
        return View("~/Views/Shared/SAAS/NotFound.cshtml");
    }
}

这是我从@mason 类复制的 ErrorLogService.cs

//common service to be used for logging errors
public static class ErrorLogService
{
    public static void LogError(Exception ex)
    {
        //Do what you want here, save log in database, send email to police station
    }
}

【讨论】:

  • 这并没有回答 OP 的问题,他的代码也没有引用 Web.config。
猜你喜欢
  • 2017-03-12
  • 2017-12-17
  • 1970-01-01
  • 2015-07-24
  • 2011-04-12
  • 1970-01-01
  • 1970-01-01
  • 2012-04-21
相关资源
最近更新 更多