【问题标题】:MVC 4 Exception handler attribute call orderMVC 4 异常处理程序属性调用顺序
【发布时间】:2013-09-27 13:24:49
【问题描述】:

问题描述:

我正在尝试创建属性,这些属性定义了如何在我的 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、一个视图、一个 StatusCodeResult,任何你想要的。在我的例子中,它总是接收一个特殊的异常类型(一些企业库的魔法),但这不是必需的。

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

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

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

提前致谢, 罗伯特

【问题讨论】:

  • 请向我们展示连接OnException 方法调用的代码。我想你可以在那里解决它。
  • FilterAttribute(我很确定)就是这样做的。另一方面,现在整个事情都被内部服务器错误覆盖了,其中包含原始异常,这几乎是我不想看到的,所以这个问题可能很快就会得到一些扩展......
  • 关于overridden-with-original-exception问题:如果我在Controller中抛出原始异常,没问题,它可以工作。如果它是来自内层的异常,它将被覆盖。奇怪的是,特别是当我捕获异常并抛出另一个异常时,它仍然会将原始异常放在结果中。
  • 所以经过一些研究,我发现 mvc 的另一部分做得不太好(恕我直言)。如果几天后我得不到答案(与我的结论不同),我会回答我自己的问题。
  • 看看这个页面msdn.microsoft.com/en-us/library/gg416513(v=vs.98).aspx,更具体地说是“过滤顺序”章节。不确定这是否会对您有所帮助,但它确实帮助我弄清楚了过滤器属性是如何被调用的。 ;-)

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


【解决方案1】:

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

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

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

我最终得到的是将我所有的“预期”异常都包含在一些自定义异常中(这可以带来很远,我有一些基本异常类,在我的异常中有一些类别,比如BusinessRuleViolationException,或DbException 等,确切的例外来自这些。)。在我的控制器中,所有操作代码都被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,具有广泛的数据库通信,这是我目前最不关心的性能问题。

【讨论】:

    猜你喜欢
    • 2018-03-20
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    • 2011-10-08
    • 1970-01-01
    • 2015-10-02
    • 1970-01-01
    相关资源
    最近更新 更多