I have a global exception filter named 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:
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:
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:
var viewModels = AutoMapper.Mapper.Map(users, new List<UserViewModel>());
Inside that AutoMapper
configuration a custom resolver executes for one of the properties:
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:
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.
What did I do wrong here?
A couple things I have done since posting:
customErrors
attribute to the Web.config
to turn them on
.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.The . NET Framework provides a couple events that can be used to catch unhandled exceptions. You only need to register for these events once in your code when your application starts up. For ASP.NET, you would do this in the Startup class or Global.
To apply the filter globally to all Web API controllers, add an instance of the filter to the GlobalConfiguration. Configuration. Filters collection. Exception filters in this collection apply to any Web API controller action.
An ExceptionFilterAttribute is used to collect unhandled exceptions. You can register it as a global filter, and it will function as a global exception handler. Another option is to use a custom middleware designed to do nothing but catch unhandled exceptions.
The short answer is that you are adding a MVC Exception Filter rather than a Web API Exception Filter.
Your implementation checks for ExceptionContext
rather than 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.
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.
public static void Register(HttpConfiguration config)
{
...
config.Filters.Add(new CustomExceptionFilter());
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With