Asp.net mvc 如何在我的Error.cshtml视图中使用过滤器放入ViewBag的数据?

Asp.net mvc 如何在我的Error.cshtml视图中使用过滤器放入ViewBag的数据?,asp.net-mvc,asp.net-mvc-3,action-filter,viewbag,Asp.net Mvc,Asp.net Mvc 3,Action Filter,Viewbag,我有一个动作过滤器,负责将一些公共信息放入ViewBag中,供shared _Layout.cshtml文件中的所有视图使用 public class ProductInfoFilterAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { // build product info

我有一个动作过滤器,负责将一些公共信息放入ViewBag中,供shared _Layout.cshtml文件中的所有视图使用

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

        dynamic viewBag = filterContext.Controller.ViewBag;
        viewBag.ProductInfo = info;
    }
}
在shared _Layout.cshtml文件中,我使用已放入ViewBag的信息

...
@ViewBag.ProductInfo.Name
...
如果在处理控制器操作时发生异常,则标准HandleErrorAttribute应显示my shared Error.cshtml视图,这在我引入上述操作筛选器并开始使用_Layout.cshtml中ViewBag中的新值之前就已经起作用了。现在我得到的是标准的ASP.Net运行时错误页面,而不是我的自定义error.cshtml视图

我已经追踪到这样一个事实:在呈现错误视图时,在_Layout.cshtml中使用ViewBag.ProductInfo.Name时会抛出RuntimeBinderException(“无法对空引用执行运行时绑定”)

看起来,即使我的操作筛选器在引发原始异常之前已成功设置ViewBag中的值,但在呈现my Error.cshtml视图时,仍会使用带有空ViewBag的新上下文


有没有办法让动作过滤器创建的数据可用于自定义错误视图?

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

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);
        }
    }
}
公共类PreserveViewDataOneExceptionFilter:IEExceptionFilter { 公共空间 OneException(例外上下文筛选器上下文) { //将视图数据内容从控制器复制到结果视图 ViewResult ViewResult=filterContext.Result作为ViewResult; 如果(viewResult!=null) {
foreach(filterContext.Controller.ViewData中的var值) { 如果(!viewResult.ViewData.ContainsKey(value.Key)) { viewResult.ViewData[value.Key]=value.value; } } } } 公共静态空间 寄存器() { 添加(新的FilterProvider()); } 私有类筛选器提供程序:IFilterProvider { 公共数字 GetFilters(ControllerContext ControllerContext、ActionDescriptor ActionDescriptor) { //将筛选器作为所有控制器/操作的“第一个”附加;注意:异常筛选器按相反顺序运行 //所以这确实会导致过滤器成为最后一个执行的过滤器 返回新筛选器(新的PreserveViewDataOneExceptionFilter(),FilterScope.First,null); } } } 需要通过调用
preserveViewDataOneExceptionFilter.Register()
将此筛选器全局挂接到Global.asax.cs
应用程序\u Start()
方法中


我在这里所做的是设置一个新的异常过滤器,该过滤器在HandleErrorAttribute过滤器运行之后最后运行,并将引发异常的控制器可用的ViewData集合的内容复制到HandleErrorAttribute筛选器创建的结果中。

这对ViewData非常有效,我喜欢这段代码,但是你有与ViewBag等效的吗?filterContext.Controller.ViewData包含我所能看到的模型和ViewBag,因此可以将其全部传递,或者仅传递所需的位