asp.net-web-api - iauthenticationfilter - web api authorization filter
¿Cuál tiene prioridad, ExceptionFilter o ExceptionHandler en ASP.NET Web Api 2.0? (1)
Tengo un ExceptionHandler global en mi api web 2.0, que maneja todas las excepciones no manejadas para devolver un mensaje de error amigable a la persona que llama api. También tengo un ExceptionFilter global, que maneja una excepción muy específica en mi api web y devuelve una respuesta específica. El ExceptionFilter se agrega dinámicamente mediante un complemento a mi api web, por lo que no puedo hacer lo que hace en mi Administrador de excepciones.
Me pregunto si tengo tanto ExceptionHandler como ExceptionFilter registrados globalmente, ¿cuál tendrá prioridad y se ejecutará primero? Ahora mismo puedo ver que el ExceptionFilter se está ejecutando antes que el ExceptionHandler. Y también puedo ver que en mi ExceptionFilter si creo una respuesta, el ExceptionHandler no se está ejecutando.
¿Será seguro asumir que:
ExceptionFilters se ejecutan antes de ExceptionHandlers.
Si el ExceptionFilter crea una respuesta, el ExceptionHandler no se ejecutará.
Tuve que depurar a través de System.Web.Http para encontrar la respuesta a mi pregunta. Así que la respuesta es:
Es seguro asumir que ExceptionFilters se ejecutará antes que ExceptionHandlers
Si ExceptionFilter crea una respuesta, ExceptionHandler no se ejecutará.
¿Por qué esto es así?
Cuando tenga un ExceptionFilter registrado para ejecutarse globalmente o para la acción de su controlador, la clase base ApiController de la que todos los controladores api heredarán envolverá el resultado en un ExceptionFilterResult y llamará a su método ExecuteAsync. Este es el código en el ApiController, que hace esto:
if (exceptionFilters.Length > 0)
{
IExceptionLogger exceptionLogger = ExceptionServices.GetLogger(controllerServices);
IExceptionHandler exceptionHandler = ExceptionServices.GetHandler(controllerServices);
result = new ExceptionFilterResult(ActionContext, exceptionFilters, exceptionLogger, exceptionHandler,
result);
}
return result.ExecuteAsync(cancellationToken);
Mirando el método ExceptionFilterResult.ExecuteAsync:
try
{
return await _innerResult.ExecuteAsync(cancellationToken);
}
catch (Exception e)
{
exceptionInfo = ExceptionDispatchInfo.Capture(e);
}
// This code path only runs if the task is faulted with an exception
Exception exception = exceptionInfo.SourceException;
Debug.Assert(exception != null);
bool isCancellationException = exception is OperationCanceledException;
ExceptionContext exceptionContext = new ExceptionContext(
exception,
ExceptionCatchBlocks.IExceptionFilter,
_context);
if (!isCancellationException)
{
// We don''t log cancellation exceptions because it doesn''t represent an error.
await _exceptionLogger.LogAsync(exceptionContext, cancellationToken);
}
HttpActionExecutedContext executedContext = new HttpActionExecutedContext(_context, exception);
// Note: exception filters need to be scheduled in the reverse order so that
// the more specific filter (e.g. Action) executes before the less specific ones (e.g. Global)
for (int i = _filters.Length - 1; i >= 0; i--)
{
IExceptionFilter exceptionFilter = _filters[i];
await exceptionFilter.ExecuteExceptionFilterAsync(executedContext, cancellationToken);
}
if (executedContext.Response == null && !isCancellationException)
{
// We don''t log cancellation exceptions because it doesn''t represent an error.
executedContext.Response = await _exceptionHandler.HandleAsync(exceptionContext, cancellationToken);
}
Puede ver que el ExceptionLogger se ejecuta primero, luego todos los ExceptionFilters se ejecutan y luego, si se ejecutaContext.Response == null, se ejecuta el ExceptionHandler.
¡Espero que esto sea útil!