全局异常过滤器或Application_Error都不是捕获未处理的异常

时间:2021-05-20 03:36:15

I have a global exception filter named LogErrorAttribute:

我有一个名为LogErrorAttribute的全局异常过滤器:

public class LogErrorAttribute : IExceptionFilter
{
    private ILogUtils logUtils;

    public void OnException(ExceptionContext filterContext)
    {
        if (this.logUtils == null)
        {
            this.logUtils = StructureMapConfig.Container.GetInstance<ILogUtils>();
        }

        this.logUtils.LogError(HttpContext.Current.User.Identity.GetUserId(), "Unknown error.", filterContext.Exception);
    }
}

It's registered along with the standard HandleErrorAttribute filter:

它与标准HandleErrorAttribute过滤器一起注册:

filters.Add(new LogErrorAttribute());
filters.Add(new HandleErrorAttribute());

I'm registering those filters like this:

我正在注册这样的过滤器:

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

I also have an Application_Error fallback:

我还有一个Application_Error后备:

protected void Application_Error()
{
    var exception = Server.GetLastError();
    Server.ClearError();
    var httpException = exception as HttpException;

    //Logging goes here

    var routeData = new RouteData();
    routeData.Values["controller"] = "Error";
    routeData.Values["action"] = "Index";

    if (httpException != null)
    {
        if (httpException.GetHttpCode() == 404)
        {
            routeData.Values["action"] = "NotFound";
        }
        Response.StatusCode = httpException.GetHttpCode();
    }
    else
    {
        Response.StatusCode = 500;
    }

    // Avoid IIS7 getting involved
    Response.TrySkipIisCustomErrors = true;

    // Execute the error controller
    if (exception != null)
    {
        this.errorLogger.Log(LogLevel.Error, "An unknown exception has occurred.", exception);
    }
    else if (httpException != null)
    {
        this.errorLogger.Log(LogLevel.Error, "An unknown HTTP exception has occurred.", httpException);
    }
    else
    {
        this.errorLogger.Log(LogLevel.Error, "An unknown error has occurred.");
    }
}

Now, I have an API controller that grabs some data from the database and then uses AutoMapper to map the models to view models:

现在,我有一个API控制器,它从数据库中获取一些数据,然后使用AutoMapper将模型映射到视图模型:

var viewModels = AutoMapper.Mapper.Map(users, new List<UserViewModel>());

Inside that AutoMapper configuration a custom resolver executes for one of the properties:

在AutoMapper配置中,自定义解析器为其中一个属性执行:

var appModuleAssignments = this.appModuleAssignmentManager.Get(userId);
var appModules = appModuleAssignments.Select(x => this.appModuleManager.Get(x.AppModuleId));
return AutoMapper.Mapper.Map(appModules, new List<AppModuleViewModel>());

At the moment I'm forcing the appModuleManager.Get statement to throw a regular exception:

目前我正在强制appModuleManager.Get语句抛出常规异常:

throw new Exception("Testing global filter.");

This subsequently throws an exception in AutoMapper, both of which are unhandled, however neither the global filter or the Application_Error are picking up this exception.

这随后会在AutoMapper中引发异常,这两个异常都是未处理的,但是全局过滤器或Application_Error都没有收到此异常。

What did I do wrong here?

我在这做错了什么?


A couple things I have done since posting:

自发布以来我做过的几件事情:

  1. Added the customErrors attribute to the Web.config to turn them on.
  2. 将customErrors属性添加到Web.config以打开它们。
  3. Removed the HandleErrorAttribute global filter because I realized it was setting the error to handled if it were even running. I would not expect it to be executing anyway because this error occurs outside the controller, but it would have likely bit me later.
  4. 删除了HandleErrorAttribute全局过滤器,因为我意识到它正在设置错误,如果它甚至在运行的话。我不希望它仍然在执行,因为这个错误发生在控制器外部,但它可能会在稍后发生。

2 个解决方案

#1


9  

The short answer is that you are adding a MVC Exception Filter rather than a Web API Exception Filter.

简短的回答是您要添加MVC异常过滤器而不是Web API异常过滤器。

Your implementation checks for ExceptionContext rather than HttpActionExecutedContext

您的实现检查ExceptionContext而不是HttpActionExecutedContext

public override void OnException(HttpActionExecutedContext actionExecutedContext)

Since the framework will raises a Http Exception rather than a MVC Exception, your OnException override method is not triggered.

由于框架将引发Http异常而不是MVC异常,因此不会触发OnException覆盖方法。

So, a more complete example:

所以,一个更完整的例子:

public class CustomExceptionFilter : ExceptionFilterAttribute

    {
       public override void OnException(HttpActionExecutedContext actionExecutedContext)

      {

        message = "Web API Error";
        status = HttpStatusCode.InternalServerError;

        actionExecutedContext.Response = new HttpResponseMessage()
        {
            Content = new StringContent(message, System.Text.Encoding.UTF8, "text/plain"),
            StatusCode = status
        };

        base.OnException(actionExecutedContext);
    }
}

Another important step is to register your Global Web API Exception Filter in WebApiConfig.cs, in the Register(HttpConfiguration config) method.

另一个重要步骤是在Register(HttpConfiguration config)方法中在WebApiConfig.cs中注册Global Web API异常过滤器。

public static void Register(HttpConfiguration config)
{

...

config.Filters.Add(new CustomExceptionFilter());

}

#2


0  

Dave Alperovich answer will solve your issue by using HttpActionExecutedContext

Dave Alperovich的回答将通过使用HttpActionExecutedContext来解决您的问题

public override void OnException(HttpActionExecutedContext context)

However as you are trying to capture all possible exceptions your application might generate then apart from exception filters one should use message handlers as well. A detailed explanation can be find here - http://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling.

但是,当您尝试捕获应用程序可能生成的所有可能异常时,除了异常过滤器之外,还应使用消息处理程序。详细解释可以在这里找到 - http://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling。

In summary, there are a number of cases that exception filters can’t handle. For example:

总之,在许多情况下,异常过滤器无法处理。例如:

  • Exceptions thrown from controller constructors.
  • 从控制器构造函数抛出的异常。
  • Exceptions thrown from message handlers.
  • 从消息处理程序抛出的异常。
  • Exceptions thrown during routing.
  • 路由期间抛出的异常。
  • Exceptions thrown during response content serialization
  • 响应内容序列化期间抛出的异常

So, If an unhandled error occurs from anywhere within the application, your Exception Handler will catch it and allow you to take specific action.

因此,如果应用程序中的任何位置发生未处理的错误,您的异常处理程序将捕获它并允许您采取特定操作。

//Global exception handler that will be used to catch any error
public class MyExceptionHandler : ExceptionHandler
    {
        private class ErrorInformation
        {
            public string Message { get; set; }
            public DateTime ErrorDate { get; set; }            
        }

        public override void Handle(ExceptionHandlerContext context)
        {
            context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError, 
              new ErrorInformation { Message="An unexpected error occured. Please try again later.", ErrorDate=DateTime.UtcNow }));
        }
   }

#1


9  

The short answer is that you are adding a MVC Exception Filter rather than a Web API Exception Filter.

简短的回答是您要添加MVC异常过滤器而不是Web API异常过滤器。

Your implementation checks for ExceptionContext rather than HttpActionExecutedContext

您的实现检查ExceptionContext而不是HttpActionExecutedContext

public override void OnException(HttpActionExecutedContext actionExecutedContext)

Since the framework will raises a Http Exception rather than a MVC Exception, your OnException override method is not triggered.

由于框架将引发Http异常而不是MVC异常,因此不会触发OnException覆盖方法。

So, a more complete example:

所以,一个更完整的例子:

public class CustomExceptionFilter : ExceptionFilterAttribute

    {
       public override void OnException(HttpActionExecutedContext actionExecutedContext)

      {

        message = "Web API Error";
        status = HttpStatusCode.InternalServerError;

        actionExecutedContext.Response = new HttpResponseMessage()
        {
            Content = new StringContent(message, System.Text.Encoding.UTF8, "text/plain"),
            StatusCode = status
        };

        base.OnException(actionExecutedContext);
    }
}

Another important step is to register your Global Web API Exception Filter in WebApiConfig.cs, in the Register(HttpConfiguration config) method.

另一个重要步骤是在Register(HttpConfiguration config)方法中在WebApiConfig.cs中注册Global Web API异常过滤器。

public static void Register(HttpConfiguration config)
{

...

config.Filters.Add(new CustomExceptionFilter());

}

#2


0  

Dave Alperovich answer will solve your issue by using HttpActionExecutedContext

Dave Alperovich的回答将通过使用HttpActionExecutedContext来解决您的问题

public override void OnException(HttpActionExecutedContext context)

However as you are trying to capture all possible exceptions your application might generate then apart from exception filters one should use message handlers as well. A detailed explanation can be find here - http://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling.

但是,当您尝试捕获应用程序可能生成的所有可能异常时,除了异常过滤器之外,还应使用消息处理程序。详细解释可以在这里找到 - http://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling。

In summary, there are a number of cases that exception filters can’t handle. For example:

总之,在许多情况下,异常过滤器无法处理。例如:

  • Exceptions thrown from controller constructors.
  • 从控制器构造函数抛出的异常。
  • Exceptions thrown from message handlers.
  • 从消息处理程序抛出的异常。
  • Exceptions thrown during routing.
  • 路由期间抛出的异常。
  • Exceptions thrown during response content serialization
  • 响应内容序列化期间抛出的异常

So, If an unhandled error occurs from anywhere within the application, your Exception Handler will catch it and allow you to take specific action.

因此,如果应用程序中的任何位置发生未处理的错误,您的异常处理程序将捕获它并允许您采取特定操作。

//Global exception handler that will be used to catch any error
public class MyExceptionHandler : ExceptionHandler
    {
        private class ErrorInformation
        {
            public string Message { get; set; }
            public DateTime ErrorDate { get; set; }            
        }

        public override void Handle(ExceptionHandlerContext context)
        {
            context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError, 
              new ErrorInformation { Message="An unexpected error occured. Please try again later.", ErrorDate=DateTime.UtcNow }));
        }
   }