我有一个 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/