MVC 4异常处理程序属性调用顺序

时间:2013-09-27 13:24:49

标签: c# asp.net-mvc-4 exception-handling

问题描述:

我正在尝试创建属性,定义如何处理ASP.NET MVC 4控制器中的异常和操作。具体来说,他们会将结果设置为返回服务器的内容。 我几乎达到了预期的效果,但是呼叫顺序有问题。 以下是我目前正在做的一个例子:

[DefaultExceptionHandler]
public abstract class BaseController
{

}

public abstract class AuthorizeController : BaseController

[VeryGoodExceptionHandler]
public class VeryGoodController : AuthorizeController
{

[ViewPageExceptionHandler]
public ActionResult ViewPage()
{
throw new Exception(); //Just for demonstration
return View();
}

public ActionResult ActionWithoutAttribute()
{
return View();
}
}

这是我的控制器的基本结构。属性都是以下类的后代:

public abstract class ExceptionHandlerAttributeBase : FilterAttribute, IExceptionFilter
    {
        public void OnException(ExceptionContext filterContext)
        {            
            filterContext.Result = CreateExceptionResult(filterContext.Exception);
        }

        protected abstract ActionResult CreateExceptionResult(Exception e);
    }

CreateExceptionResult可以返回JsonResult,View,StatusCodeResult,无论你想要什么。在我的情况下,它总是会收到一个特殊的异常类型(Some Enterprise Library magic),但这不是必需的。

该属性工作得很好,我把它放在某个东西上,OnException方法被调用就像它应该的那样,将正确的ActionResult放在filterContext中,然后将它发送回客户端。 当我想覆盖属性时,问题就开始了。它发生了,每个OnException方法都被调用,具有相同的上下文。当只有控制器被装饰时,一切都(几乎)很好,首先,调用放置在BaseController上的那个,然后调用“VeryGoodController”,覆盖结果。摆脱基本呼叫会很好,但无论如何。在Action和控制器修饰的情况下,调用顺序恰好是:action属性的OnException(设置所需的结果),基本控制器的OnException和子控制器的OnException(覆盖所需的结果)。 ExceptionContext没有任何属性可用作进一步处理的标志(也许Exception属性可以设置为null,但这不是我要做的事情。)

问题: 所以问题是我怎样才能获得a)获取最后调用Action的OnException方法,和/或如果可能的话b)拒绝调用不太具体的方法(以更有效的方式,然后得到他们的结果重写)?

一些额外信息: 我使用this答案作为参考。 另外,如果我按照本文所述的方式注册过滤器,并且不添加属性,则会发生同样的情况。

提前致谢, 罗伯特

1 个答案:

答案 0 :(得分:2)

事实证明,我完全错误地认为可以做到这样的事情。

根据this博客文章(据我所知,我设法在我自己的代码上测试),整个异常过滤器的东西(即使我只是覆盖了Controller.OnException方法) ,非常有限,只适用于某些情况。我能找到的唯一(不太吸引人的)替代方法是在每个控制器方法中处理一些辅助类中的异常,这些异常是从通用异常助手调用的。另一种方法是在Application_Error块中编写一些令人厌恶的代码,然后在那里处理。

博客文章提到了一个图书馆,这在理论上是非常好的,但描述中的“捕获大多数例外”并不是很吸引人。

我最终得到的是,将所有“预期”异常包含在一些自定义异常中(这可以带来很多,我有一些基本异常类,在我的异常上有一些类别,如{{1} },或BusinessRuleViolationException等,确切的例外情况来自这些。)。在我的控制器中,所有操作代码都被DbException块包围,并且只有一个try块。该块调用我的exceptionhandler实用程序类的handleexception函数,并返回结果。

异常处理函数:

catch(Exception e)

现在就是这样,作为最后一道防线,一些代码应该放在Application_Error函数中,严格地消除任何信息泄漏的可能性,并记录是否有任何东西(可能是严重错误)。 异常处理函数可以进行参数化,以便能够提供不同的结果(如ajax场景中的StatusCode,但在标准场景中出现错误View),所以我相信这个解决方案非常灵活,而且基本上是最不可能的丑陋。我有点担心抛出异常的数量,但是,这是一个MVC 4 webapp,具有广泛的数据库通信,这是我现在最不关心的性能问题。