asp.net-mvc - 如何使用 Error.cshtml View 中的过滤器放入 ViewBag 的数据?

标签 asp.net-mvc asp.net-mvc-3 action-filter viewbag

我有一个 Action 过滤器,负责将一些通用信息放入 ViewBag 中,以供共享 _Layout.cshtml 文件中的所有 View 使用。

public class ProductInfoFilterAttribute : ActionFilterAttribute
{
    public override void
    OnActionExecuting(ActionExecutingContext filterContext)
    {
        //  build product info
        //  ... (code omitted)

        dynamic viewBag = filterContext.Controller.ViewBag;
        viewBag.ProductInfo = info;
    }
}

在共享的_Layout.cshtml 文件中,我使用了已放入ViewBag 的信息。
...
@ViewBag.ProductInfo.Name
...

如果在处理 Controller 操作时发生异常,标准的 HandleErrorAttribute 应该显示我共享的 Error.cshtml View ,这在我引入上面的操作过滤器并开始使用 _Layout.cshtml 中的 ViewBag 的新值之前有效。现在我得到的是标准的 ASP.Net 运行时错误页面,而不是我的自定义 Error.cshtml View 。

我已将此归结为以下事实:在呈现错误 View 时,在 _Layout.cshtml 中使用 ViewBag.ProductInfo.Name 时会引发 RuntimeBinderException(“无法对空引用执行运行时绑定(bind)”)。

看起来即使我的操作过滤器在引发原始异常之前已成功设置 ViewBag 中的值,但在呈现我的 Error.cshtml View 时仍使用具有空 ViewBag 的新上下文。

有什么方法可以让操作过滤器创建的数据可用于自定义错误 View ?

最佳答案

我通过添加另一个过滤器提出了自己的解决方案。

public class PreserveViewDataOnExceptionFilter : IExceptionFilter
{
    public void
    OnException(ExceptionContext filterContext)
    {
        //  copy view data contents from controller to result view
        ViewResult viewResult = filterContext.Result as ViewResult;
        if ( viewResult != null )
        {
            foreach ( var value in filterContext.Controller.ViewData )
            {
                if ( ! viewResult.ViewData.ContainsKey(value.Key) )
                {
                    viewResult.ViewData[value.Key] = value.Value;
                }
            }
        }
    }

    public static void
    Register()
    {
        FilterProviders.Providers.Add(new FilterProvider());
    }

    private class FilterProvider : IFilterProvider
    {
        public IEnumerable<Filter>
        GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            //  attach filter as "first" for all controllers / actions; note: exception filters run in reverse order
            //  so this really causes the filter to be the last filter to execute
            yield return new Filter(new PreserveViewDataOnExceptionFilter(), FilterScope.First, null);
        }
    }
}

此过滤器需要在 Global.asax.cs Application_Start() 中全局 Hook 通过调用 PreserveViewDataOnExceptionFilter.Register() 的方法.

我在这里所做的是设置一个新的异常过滤器,该过滤器在 HandleErrorAttribute 过滤器运行之后最后运行,并将 ViewData 集合的内容复制给将异常抛出到由 HandleErrorAttribute 过滤器创建的结果的 Controller .

关于asp.net-mvc - 如何使用 Error.cshtml View 中的过滤器放入 ViewBag 的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6602638/

相关文章:

c# - CaSTLe Windsor激活错误IController,key "home"

asp.net-mvc - 检查 DateTime 类型的值是否在 View 中为空,如果为空则显示空白

xml - SyntaxHighlighter 不格式化 xml 文本

ASP.NET MVC Html.textbox - 如何只验证数字?

c# - MVC Controller 需要空构造函数,但未使用接口(interface)并抛出错误

asp.net-mvc-3 - 使用 ASP.NET 成员(member)提供程序从 MVC3 站点进行 TNS oracle 连接失败

c# - C# 中 Linq 查询中的枚举条件

c# - OnActionExecuting 在开始行动之前添加到模型

asp.net-mvc - 如何在全局级别添加 AuthorizeAttribute 并在某些操作中排除它?