c# - net - web api exception handling best practice
¿Necesita una muestra completa para manejar las excepciones no controladas usando "ExceptionHandler" en ASP.NET Web Api? (4)
Había revisado este enlace http://www.asp.net/web-api/overview/web-api-routing-and-actions/web-api-global-error-handling . En este enlace, mencionaron así
class OopsExceptionHandler : ExceptionHandler
{
public override void HandleCore(ExceptionHandlerContext context)
{
context.Result = new TextPlainErrorResult
{
Request = context.ExceptionContext.Request,
Content = "Oops! Sorry! Something went wrong." +
"Please contact [email protected] so we can try to fix it."
};
}
private class TextPlainErrorResult : IHttpActionResult
{
public HttpRequestMessage Request { get; set; }
public string Content { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response =
new HttpResponseMessage(HttpStatusCode.InternalServerError);
response.Content = new StringContent(Content);
response.RequestMessage = Request;
return Task.FromResult(response);
}
}
}
No sé cómo llamar a esta clase en mis acciones de API web. Entonces, ¿alguien puede darme la muestra completa usando este ExceptionHandler
?
No necesita implementar el mecanismo de bajo nivel IExceptionHandler usted mismo.
En cambio, simplemente puede heredar desde ExceptionHandler y anular el método Handle .
public class MyExceptionHandler : ExceptionHandler
{
public override void Handle(ExceptionHandlerContext context)
{
//TODO: Do what you need to do
base.Handle(context);
}
}
ExceptionHandler implementa IExceptionHandler y gestiona los mecanismos básicos básicos (como async y esa excepción debe ser manejada o no).
Use su manejador de excepciones así:
config.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());
Fuente
http://www.asp.net/web-api/overview/web-api-routing-and-actions/web-api-global-error-handling explica cómo implementar IExceptionHandler, pero hay algunos errores tipográficos y el código no refleja la última versión de WebApi.
No hay documentación sobre el espacio de nombres System.Web.Http.ExceptionHandling
(un poco sobre NuDoq ).
Entonces ... usando un descompilador de ensamblados .NET que mira el código fuente en GitHub , vi la clase ExceptionHandler
que implementa IExceptionHandler
y tiene algunos métodos virtuales.
ExceptionHandler se ve así:
namespace System.Web.Http.ExceptionHandling
{
/// <summary>Represents an unhandled exception handler.</summary>
public abstract class ExceptionHandler : IExceptionHandler
{
/// <returns>Returns <see cref="T:System.Threading.Tasks.Task" />.</returns>
Task IExceptionHandler.HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
ExceptionContext arg_14_0 = context.ExceptionContext;
if (!this.ShouldHandle(context))
{
return TaskHelpers.Completed();
}
return this.HandleAsync(context, cancellationToken);
}
/// <summary>When overridden in a derived class, handles the exception asynchronously.</summary>
/// <returns>A task representing the asynchronous exception handling operation.</returns>
/// <param name="context">The exception handler context.</param>
/// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
public virtual Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
this.Handle(context);
return TaskHelpers.Completed();
}
/// <summary>When overridden in a derived class, handles the exception synchronously.</summary>
/// <param name="context">The exception handler context.</param>
public virtual void Handle(ExceptionHandlerContext context)
{
}
/// <summary>Determines whether the exception should be handled.</summary>
/// <returns>true if the exception should be handled; otherwise, false.</returns>
/// <param name="context">The exception handler context.</param>
public virtual bool ShouldHandle(ExceptionHandlerContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
ExceptionContext exceptionContext = context.ExceptionContext;
ExceptionContextCatchBlock catchBlock = exceptionContext.CatchBlock;
return catchBlock.IsTopLevel;
}
}
}
Puede ver claramente que ShouldHandle
se implementa usando ExceptionContextCatchBlock.IsTopLevel
y que HandleAsync
llama a Handle
:)
Espero que esto ayude hasta que aparezca una documentación completa.
En su configuración de WebApi, necesita agregar la línea:
config.Services.Replace(typeof (IExceptionHandler), new OopsExceptionHandler());
También asegúrese de haber creado la clase base ExceptionHandler que implementa IExceptionHandler:
public class ExceptionHandler : IExceptionHandler
{
public virtual Task HandleAsync(ExceptionHandlerContext context,
CancellationToken cancellationToken)
{
if (!ShouldHandle(context))
{
return Task.FromResult(0);
}
return HandleAsyncCore(context, cancellationToken);
}
public virtual Task HandleAsyncCore(ExceptionHandlerContext context,
CancellationToken cancellationToken)
{
HandleCore(context);
return Task.FromResult(0);
}
public virtual void HandleCore(ExceptionHandlerContext context)
{
}
public virtual bool ShouldHandle(ExceptionHandlerContext context)
{
return context.ExceptionContext.IsOutermostCatchBlock;
}
}
Tenga en cuenta que esto solo tratará con excepciones que no se manejan en otro lado (por ejemplo, mediante filtros de excepción).
Puede echar un vistazo a la siguiente muestra del equipo de la API web:
http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/Elmah/ReadMe.txt
Según la respuesta de Jon Susiak, necesitas usar:
config.Services.Replace(typeof (IExceptionHandler), new OopsExceptionHandler());
Tenga en cuenta la llamada Replace
, no un Add
. La razón de esto es según el artículo en este enlace:
Manejo global de errores en ASP.NET Web API 2
Descripción de la solución
Proporcionamos dos nuevos servicios reemplazables por el usuario, IExceptionLogger e IExceptionHandler, para registrar y manejar excepciones no controladas.
Los servicios son muy similares, con dos diferencias principales:
Admitimos registrar múltiples registradores de excepción pero solo un único manejador de excepciones .
Y como ya hay un controlador registrado por defecto, no puede agregar otro.
public DefaultServices(HttpConfiguration configuration)
{
if (configuration == null)
throw System.Web.Http.Error.ArgumentNull("configuration");
this._configuration = configuration;
this.SetSingle<IActionValueBinder>((IActionValueBinder) new DefaultActionValueBinder());
this.SetSingle<IApiExplorer>((IApiExplorer) new ApiExplorer(configuration));
this.SetSingle<IAssembliesResolver>((IAssembliesResolver) new DefaultAssembliesResolver());
this.SetSingle<IBodyModelValidator>((IBodyModelValidator) new DefaultBodyModelValidator());
this.SetSingle<IContentNegotiator>((IContentNegotiator) new DefaultContentNegotiator());
this.SetSingle<IDocumentationProvider>((IDocumentationProvider) null);
this.SetMultiple<IFilterProvider>((IFilterProvider) new ConfigurationFilterProvider(), (IFilterProvider) new ActionDescriptorFilterProvider());
this.SetSingle<IHostBufferPolicySelector>((IHostBufferPolicySelector) null);
this.SetSingle<IHttpActionInvoker>((IHttpActionInvoker) new ApiControllerActionInvoker());
this.SetSingle<IHttpActionSelector>((IHttpActionSelector) new ApiControllerActionSelector());
this.SetSingle<IHttpControllerActivator>((IHttpControllerActivator) new DefaultHttpControllerActivator());
this.SetSingle<IHttpControllerSelector>((IHttpControllerSelector) new DefaultHttpControllerSelector(configuration));
this.SetSingle<IHttpControllerTypeResolver>((IHttpControllerTypeResolver) new DefaultHttpControllerTypeResolver());
this.SetSingle<ITraceManager>((ITraceManager) new TraceManager());
this.SetSingle<ITraceWriter>((ITraceWriter) null);
this.SetMultiple<ModelBinderProvider>((ModelBinderProvider) new TypeConverterModelBinderProvider(), (ModelBinderProvider) new TypeMatchModelBinderProvider(), (ModelBinderProvider) new KeyValuePairModelBinderProvider(), (ModelBinderProvider) new ComplexModelDtoModelBinderProvider(), (ModelBinderProvider) new ArrayModelBinderProvider(), (ModelBinderProvider) new DictionaryModelBinderProvider(), (ModelBinderProvider) new CollectionModelBinderProvider(), (ModelBinderProvider) new MutableObjectModelBinderProvider());
this.SetSingle<ModelMetadataProvider>((ModelMetadataProvider) new DataAnnotationsModelMetadataProvider());
this.SetMultiple<ModelValidatorProvider>((ModelValidatorProvider) new DataAnnotationsModelValidatorProvider(), (ModelValidatorProvider) new DataMemberModelValidatorProvider());
this.SetMultiple<ValueProviderFactory>((ValueProviderFactory) new QueryStringValueProviderFactory(), (ValueProviderFactory) new RouteDataValueProviderFactory());
this.SetSingle<IModelValidatorCache>((IModelValidatorCache) new ModelValidatorCache(new Lazy<IEnumerable<ModelValidatorProvider>>((Func<IEnumerable<ModelValidatorProvider>>) (() => ServicesExtensions.GetModelValidatorProviders((ServicesContainer) this)))));
this.SetSingle<IExceptionHandler>((IExceptionHandler) new DefaultExceptionHandler());
this.SetMultiple<IExceptionLogger>();
this._serviceTypesSingle = new HashSet<Type>((IEnumerable<Type>) this._defaultServicesSingle.Keys);
this._serviceTypesMulti = new HashSet<Type>((IEnumerable<Type>) this._defaultServicesMulti.Keys);
this.ResetCache();
}