在ASP.NET Web Api中使用“ExceptionHandler”需要一个完整的示例来处理未处理的异常?

问题描述 投票:31回答:4

我查看了这个链接http://www.asp.net/web-api/overview/web-api-routing-and-actions/web-api-global-error-handling。在这个链接中他们提到了这样的

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

我不知道如何在我的Web API操作中调用此类。所以任何人都可以使用这个ExceptionHandler给我完整的样本。

c# asp.net-web-api exception-handling
4个回答
29
投票

在您的WebApi配置中,您需要添加以下行:

config.Services.Replace(typeof (IExceptionHandler), new OopsExceptionHandler());

还要确保已创建实现IExceptionHandler的基本ExceptionHandler类:

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.CatchBlock.IsTopLevel;
    }
} 

请注意,这只会处理其他地方未处理的异常(例如,通过异常过滤器)。


84
投票

您不需要自己实现IExceptionHandler低级机制。

相反,您可以简单地从ExceptionHandler继承并覆盖Handle方法。

public class MyExceptionHandler: ExceptionHandler
{
  public override void Handle(ExceptionHandlerContext context)
  {
    //TODO: Do what you need to do
    base.Handle(context);
  }
}

ExceptionHandler实现IExceptionHandler并管理基本核心机制(如异步和异常应该处理或不处理)。

像这样使用你的异常处理程序:

config.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());

资源

This page解释了如何实现IExceptionHandler,但是有一些拼写错误并且代码没有反映最新版本的WebApi。

没有关于System.Web.Http.ExceptionHandling命名空间的文档(有点像NuDoq)。

所以.. 使用.NET assembly decompiler 看看the source code on GitHub,我看到ExceptionHandler类实现了IExceptionHandler并且有一些虚拟方法。

ExceptionHandler看起来像这样:

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

您可以清楚地看到ShouldHandle是使用ExceptionContextCatchBlock.IsTopLevel实现的,HandleAsync调用Handle :)

我希望这会有所帮助,直到完整的文档显示出来。


4
投票

根据Jon Susiak的回答,您需要使用:

config.Services.Replace(typeof (IExceptionHandler), new OopsExceptionHandler());

请注意Replace电话,而不是Add。原因是根据此链接中的文章:

Global Error Handling in ASP.NET Web API 2

方案概述

我们提供了两个新的用户可替换服务IExceptionLogger和IExceptionHandler来记录和处理未处理的异常。

服务非常相似,有两个主要区别:

我们支持注册多个异常记录器,但只支持一个异常处理程序。

由于默认情况下已经注册了处理程序,因此无法添加其他处理程序。

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

0
投票
© www.soinside.com 2019 - 2024. All rights reserved.