异常处理 – 如何处理WebAPI中的控制器构造函数中的异常?

前端之家收集整理的这篇文章主要介绍了异常处理 – 如何处理WebAPI中的控制器构造函数中的异常?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
说我有一个构造函数,它的初始化可能会由于我无法控制的原因而抛出异常.
FantasticApiController(IAwesomeGenerator awesome,IBusinessRepository repository,IIceCreamFactory factory)
{
       Awesome = awesome;
       Repository = repository;
       IceCream = factory.MakeIceCream();

       DoSomeInitialization(); // this can throw an exception
}

通常,当WebAPI中的Controller操作抛出异常时,我可以通过一个csutom ExceptionFilterAttribute来处理它:

public class CustomErrorHandler
{
    public override void OnException(HttpActionExecutedContext context)
    {
        // Critical error,this is real bad.
        if (context.Exception is BubonicPlagueException)
        {
            Log.Error(context.Exception,"CLOSE EVERYTHING!");
            Madagascar.ShutdownAllPorts();
        }

        // No big deal,just show something user friendly
        throw new HttpResponseException(new HttpResponseMessage
        {
            Content = new StringContent("Hey something bad happened. " +
                                        "Not closing the ports though"),StatusCode = HttpStatusCode.InternalServerError;
        });
    }

所以如果我有一个BoardPlane API方法抛出一个BubonicPlagueException,那么我的CustomerErrorHandler将关闭端口到马达加斯加,并按预期的方式将其记录为一个错误.在其他情况下,当它不是很严重时,我只显示一些用户友好的消息并返回500 InternalServerError.

但是在DoSomeInitialization引发异常的情况下,这绝对没有.如何处理WebAPI控制器构造函数中的异常?

解决方法

创建WebApi控制器,因此通过HttpControllerActivators调用构造函数.默认的激活器是System.Web.Http.Dispatcher.DefaultHttpControllerActivator.

选项1& 2在github这里https://github.com/markyjones/StackOverflow/tree/master/ControllerExceptionHandling/src

方案1的工作相当不错,涉及使用DI容器(您可能已经使用了一个).我使用Ninject作为我的例子,并使用“Interceptor”Read More拦截并尝试/捕获对DefaultHttpControllerActivator的Create方法调用.我至少知道AutoFac和Ninject可以做一些类似于以下的事情:

创建拦截

我不知道你的马达加斯加和日志项目的生命周期是什么,但是他们可以很好地注入到你的拦截器中

public class ControllerCreationInterceptor : Ninject.Extensions.Interception.IInterceptor
{
    private ILog _log;
    private IMadagascar _madagascar;

    public ControllerCreationInterceptor(ILog log,IMadagascar madagascar)
    {
        _log = log;
        _madagascar = madagascar;
    }

但是,请记住在你的问题中,Log和Madagascar是一种静态全局的例子

public class ControllerCreationInterceptor : Ninject.Extensions.Interception.IInterceptor
{

    public void Intercept(Ninject.Extensions.Interception.IInvocation invocation)
    {
        try
        {
            invocation.Proceed();
        }
        catch(InvalidOperationException e)
        {
            if (e.InnerException is BubonicPlagueException)
            {
                Log.Error(e.InnerException,"CLOSE EVERYTHING!");
                Madagascar.ShutdownAllPorts();
                //DO SOMETHING WITH THE ORIGIONAL ERROR!
            }
            //DO SOMETHING WITH THE ORIGIONAL ERROR!
        }
    }
}

最终注册拦截器在全局asax或App_Start(NinjectWebCommon)

kernel.Bind<System.Web.Http.Dispatcher.IHttpControllerActivator>()
            .To<System.Web.Http.Dispatcher.DefaultHttpControllerActivator>().Intercept().With<ControllerCreationInterceptor>();

选项2是实现自己的Controller Activator实现IHttpControllerActivator接口,并在Create方法中处理创建Controller的错误.您可以使用装饰器图案来包装DefaultHttpControllerActivator:

public class YourCustomControllerActivator : IHttpControllerActivator
{
    private readonly IHttpControllerActivator _default = new DefaultHttpControllerActivator();

    public YourCustomControllerActivator()
    {

    }

     public System.Web.Http.Controllers.IHttpController Create(System.Net.Http.HttpRequestMessage request,System.Web.Http.Controllers.HttpControllerDescriptor controllerDescriptor,Type controllerType)
    {
        try
        {
            return _default.Create(request,controllerDescriptor,controllerType);
        }
        catch (InvalidOperationException e)
        {
            if (e.InnerException is BubonicPlagueException)
            {
                Log.Error(e.InnerException,"CLOSE EVERYTHING!");
                Madagascar.ShutdownAllPorts();
                //DO SOMETHING WITH THE ORIGIONAL ERROR!
            }
            //DO SOMETHING WITH THE ORIGIONAL ERROR!
            return null;
        }

    }
}

一旦你有自己的定制激活器,默认的激活器可以是全局asax中的switched out

GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator),new YourCustomControllerActivator());

选项3当然,如果您在构造函数中的初始化不需要访问实际的Controllers方法,属性等,即假设可以从构造函数删除…那么将初始化变为一个过滤器

public class MadagascarFilter : AbstractActionFilter
{
    public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
    try{
          DoSomeInitialization(); // this can throw an exception
        }
        catch(BubonicPlagueException e){
    Log.Error(e,"CLOSE EVERYTHING!");
        Madagascar.ShutdownAllPorts();
            //DO SOMETHING WITH THE ERROR                           
        }

        base.OnActionExecuting(actionContext);
    }

public override void OnActionExecuted(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
    {
        base.OnActionExecuted(actionExecutedContext);
    }

    public override bool AllowMultiple
    {
        get { return false; }
    }


}

猜你在找的asp.Net相关文章