Following the discussion from the official documentation on implementing an IExceptionLogger
(http://www.asp.net/web-api/overview/testing-and-debugging/web-api-global-error-handling) which links to the (now dated?) article on implementing an ExceptionFilterAttribute
(http://www.asp.net/web-api/overview/testing-and-debugging/exception-handling), is there any reason to register a global ExceptionFilterAttribute
if you register a service for IExceptionLogger
?
I did and when debugging an exception generated in a controller action, both implementations handled the exception. So IExceptionLogger
is superior for all the reasons cited in the article. Should we consider ExceptionFilterAttribute
deprecated? If not, why not?
Revisiting this topic, I finally have a better understanding of the relationship between IExceptionLogger
, ExceptionFilterAttribute
, and IExceptionHandler
.
From a different source of documentation from the question:
We provide two new user-replaceable services, IExceptionLogger and IExceptionHandler, to log and handle unhandled exceptions. The services are very similar, with two main differences: We support registering multiple exception loggers but only a single exception handler. Exception loggers always get called, even if we’re about to abort the connection. Exception handlers only get called when we’re still able to choose which response message to send. Both services provide access to an exception context containing relevant information from the point where the exception was detected, particularly the HttpRequestMessage, the HttpRequestContext, the thrown exception and the exception source (details below).
And the actual answer to the question:
Exception loggers are the solution to seeing all unhandled exception caught by Web API. Exception handlers are the solution for customizing all possible responses to unhandled exceptions caught by Web API. Exception filters are the easiest solution for processing the subset unhandled exceptions related to a specific action or controller.
And the relevant block of code that illustrates the relationship between the various classes/interfaces (decompiled from ExceptionFilterResult
):
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
ExceptionDispatchInfo exceptionInfo;
try
{
return await this._innerResult.ExecuteAsync(cancellationToken);
}
catch (Exception ex)
{
exceptionInfo = ExceptionDispatchInfo.Capture(ex);
}
Exception exception = exceptionInfo.SourceException;
bool isCancellationException = exception is OperationCanceledException;
ExceptionContext exceptionContext = new ExceptionContext(exception, ExceptionCatchBlocks.IExceptionFilter, this._context);
if (!isCancellationException)
await this._exceptionLogger.LogAsync(exceptionContext, cancellationToken);
HttpActionExecutedContext executedContext = new HttpActionExecutedContext(this._context, exception);
for (int i = this._filters.Length - 1; i >= 0; --i)
{
IExceptionFilter exceptionFilter = this._filters[i];
await exceptionFilter.ExecuteExceptionFilterAsync(executedContext, cancellationToken);
}
if (executedContext.Response == null && !isCancellationException)
executedContext.Response = await this._exceptionHandler.HandleAsync(exceptionContext, cancellationToken);
if (executedContext.Response != null)
return executedContext.Response;
if (exception == executedContext.Exception)
exceptionInfo.Throw();
throw executedContext.Exception;
}
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