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

本文关键字:调用 顺序 属性 异常处理程序 MVC | 更新日期: 2023-09-27 18:32:59

问题描述:

我正在尝试创建属性,这些属性定义如何处理 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、视图、状态代码结果,任何你想要的。就我而言,它总是收到一个特殊的异常类型(一些企业库魔术(,但这不是必需的。

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

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

一些额外信息:我用这个答案作为参考。另外,如果我以本文中描述的方式注册过滤器,并且不添加属性,也会发生同样的情况。

提前感谢,罗伯特

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

所以事实证明,我期望这样的事情可以做到是完全错误的。

根据这篇博文(据我所知,我设法在自己的代码上测试的内容证实了这一点(,整个异常过滤器的东西(即使我只是覆盖了 Controller.OnException 方法(非常有限,并且仅适用于某些场景。我能找到的唯一(不是很吸引人的(替代方案是在每个控制器方法中处理从通用异常帮助程序调用的某个帮助程序类中的异常。另一种选择是在Application_Error块中编写一些特别恶心的代码,并在那里处理东西。

博客文章提到了一个库,它(理论上(非常好,但描述中的"捕获大多数例外"并不是很吸引人。

最终得到的是将所有"预期"异常包装在一些自定义异常中(这可以走得很远,我有一些基本的异常类,在我的异常上有一些类别,如BusinessRuleViolationExceptionDbException等,确切的异常是从这些派生出来的。在我的控制器中,所有操作代码都用一个try块包围,并且只有一个catch(Exception e)块。此块调用我的异常处理程序实用程序类的 handleexception 函数,并返回结果。

异常处理程序函数:

public static ActionResult HandleException(Exception e)
        {
            try
            {
                //Calling the EL exception handler block. Configured to rethrow a HandledException.
                ExceptionPolicy.HandleException(e, ExceptionPolicyName.StatusCodePolicy.GetCode());
                //If no exception happened, that is a problem. Internal Server Error, also logging should be done.
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
            }
            //Catch the HandledException. It contains only controlled info on the error, which can be sent to the client. Also, the original exception is already logged by this time.
            catch (HandledException ex)
            {              
                return new HttpStatusCodeResult(ex.StatusCode, ex.Message);
            }
            catch (Exception ex)
            {
                //If the exception was not a HandledException (very unlikely), that is a problem, it should be logged. Also, Internal Server Error.
                return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
            }
        }

现在就是这样,作为最后一道防线,应该在Application_Error函数中放入一些代码,严格消除任何信息泄露的机会,并记录是否有任何东西到达那里(大概是严重错误(。异常处理程序函数可以参数化,以便能够提供不同的结果(例如 ajax 场景中的 StatusCode,但在标准场景中的错误视图(,所以我相信这个解决方案非常灵活,基本上是最不丑陋的可能性。我有点担心抛出异常的数量,但是meh,这是一个MVC 4 web应用程序,具有广泛的数据库通信,这是我目前最不关心的性能问题。