2

问题描述:

我正在尝试创建属性,定义如何在我的 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,无论你想要什么。在我的情况下,它总是接收一个特殊的异常类型(一些企业库魔法),但这不是必需的。

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

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

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

在此先感谢,罗伯特

4

1 回答 1

2

事实证明,我完全错误地期望可以完成这样的事情。

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

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

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

异常处理函数:

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,但标准场景中的错误视图),所以我相信这个解决方案非常灵活,基本上是最不难看的可能性。我有点担心抛出异常的数量,但是,嗯,这是一个 MVC 4 webapp,具有广泛的数据库通信,这是我目前最不关心的性能问题。

于 2013-10-02T07:56:16.643 回答