Как передать ViewData представлению HandleError?
В моем файле 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);
}
}
Проблема, с которой я столкнулся, заключается в том, что эти значения не передаются в MyErrorView (и, в конечном счете, Site.Master), когда HandleErrorAttribute включается из атрибута уровня класса SiteController. Вот простой сценарий, чтобы показать мою проблему:
public class TestingController : SiteController
{
public ActionResult DoSomething()
{
throw new MyException("pwnd!");
}
}
Я попытался заполнить параметры ViewData, переопределив метод OnException() в моем SiteController, но безрезультатно.:(
Каков наилучший способ передачи параметров ViewData моему Site.Master в этом случае?
2 ответа
Это связано с тем, что HandleErrorAttribute изменяет данные ViewData, передаваемые представлению при возникновении ошибки. Он передает экземпляр класса HandleErrorInfo с информацией об Exception, Controller и Action.
Что вы можете сделать, это заменить этот атрибут на тот, который реализован ниже:
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;
}
}
}
}
Если вам просто нужно передать что-то через 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);
}
См. Здесь: Как я могу использовать данные, помещенные в ViewBag фильтром в моем представлении Error.cshtml?