14

在我的 Site.Master 文件中,我有 3 个简单的 ViewData 参数(整个解决方案中只有 3 个)。这些 ViewData 值对于我的应用程序中的每个页面都至关重要。由于在我的 Site.Master 中使用了这些值,因此我创建了一个抽象的 SiteController 类,它覆盖 OnActionExecuting 方法来为我的解决方案中每个控制器上的每个 Action 方法填充这些值。

[HandleError(ExceptionType=typeof(MyException), View="MyErrorView")]
public abstract class SiteController : Controller
{
  protected override void OnActionExecuting(...)
  {
    ViewData["Theme"] = "BlueTheme";
    ViewData["SiteName"] = "Company XYZ Web Portal";
    ViewData["HeaderMessage"] = "Some message...";        

    base.OnActionExecuting(filterContext);

  }
}

我面临的问题是,当 HandleErrorAttribute 从 SiteController 类级别属性启动时,这些值没有传递给 MyErrorView(最终是 Site.Master)。这是一个简单的场景来显示我的问题:

public class TestingController : SiteController
{
  public ActionResult DoSomething()
  {
    throw new MyException("pwnd!");
  }
}

我也尝试通过覆盖 SiteController 中的 OnException() 方法来填充 ViewData 参数,但无济于事。:(

在这种情况下,将 ViewData 参数传递给我的 Site.Master 的最佳方法是什么?

4

2 回答 2

21

这是因为当发生错误时,HandleErrorAttribute 会更改传递给视图的 ViewData。它传递一个 HandleErrorInfo 类的实例,其中包含有关异常、控制器和操作的信息。

您可以做的是将此属性替换为以下实现的属性:

using System;
using System.Web;
using System.Web.Mvc;

public class MyHandleErrorAttribute : HandleErrorAttribute {

    public override void OnException(ExceptionContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }
        if (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled)
        {
            Exception innerException = filterContext.Exception;
            if ((new HttpException(null, innerException).GetHttpCode() == 500) && this.ExceptionType.IsInstanceOfType(innerException))
            {
                string controllerName = (string) filterContext.RouteData.Values["controller"];
                string actionName = (string) filterContext.RouteData.Values["action"];
                // Preserve old ViewData here
                var viewData = new ViewDataDictionary<HandleErrorInfo>(filterContext.Controller.ViewData); 
                // Set the Exception information model here
                viewData.Model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
                filterContext.Result = new ViewResult { ViewName = this.View, MasterName = this.Master, ViewData = viewData, TempData = filterContext.Controller.TempData };
                filterContext.ExceptionHandled = true;
                filterContext.HttpContext.Response.Clear();
                filterContext.HttpContext.Response.StatusCode = 500;
                filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            }
        }
    }
}
于 2009-11-25T06:13:41.077 回答
3

如果您只需要通过 ViewBag 传递一些东西,可以这样做:(这恰好在 BaseController 中,我的所有控制器都继承自)

    protected override void OnException(ExceptionContext filterContext)
    {
        try
        {
            var v = filterContext.Result as ViewResult;
            v.ViewBag.DataToPassToError = "Hello World!";
        }
        catch { /* no-op */ }

        base.OnException(filterContext);
    }

请参阅此处:如何使用 Error.cshtml 视图中的过滤器放入 ViewBag 的数据?

于 2013-04-08T23:29:37.090 回答