15

Ho un ExceptionHandler globale nel mio Web API 2.0, che gestisce tutte le eccezioni non gestite per restituire un messaggio di errore amichevole al chiamante API. Ho anche un ExceptionFilter globale, che gestisce un'eccezione molto specifica nella mia web api e restituisce una risposta specifica. ExceptionFilter viene aggiunto dinamicamente da un plugin alla mia web api quindi non posso fare quello che fa nel mio ExceptionHandler.Quale ha priorità, ExceptionFilter o ExceptionHandler in ASP.NET Web Api 2.0?

Mi chiedo se sono registrati sia ExceptionHandler che ExceptionFilter globalmente, quale avrà priorità e verrà eseguito per primo? In questo momento posso vedere che ExceptionFilter viene eseguito prima di ExceptionHandler. E posso anche vedere che nel mio ExceptionFilter se creo una risposta non viene eseguito ExceptionHandler.

sarà sicuro presumere che:

  1. ExceptionFilters vengono eseguite prima ExceptionHandlers.

  2. Se ExceptionFilter crea una risposta, ExceptionHandler non verrà eseguito.

risposta

25

Ho dovuto eseguire il debug attraverso System.Web.Http per trovare la risposta alla mia domanda. Quindi la risposta è:

  1. E 'lecito ritenere che ExceptionFilters verranno eseguiti prima ExceptionHandlers

  2. Se l'ExceptionFilter crea una risposta l'ExceptionHandler non sarebbe stato giustiziato.

perché questo è così:

Quando si dispone di un ExceptionFilter registrata per l'esecuzione a livello globale o per il vostro azione di controllo, la classe base ApiController da cui tutti i controller di api ereditano andrà a capo il risultato in un ExceptionFilterResult e chiama il suo metodo ExecuteAsync. Questo è il codice nel ApiController, che fa questo:

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); 

Guardando il metodo 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); 
} 

Si può vedere che l'ExceptionLogger viene eseguito per primo, poi tutti sono ExceptionFilters eseguito e, quindi, se eseguitoContext.Response == null, viene eseguito ExceptionHandler.

Spero sia utile!