Подтвердить что ты не робот

Как передать 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 в этом случае?

4b9b3361

Ответ 1

Это связано с тем, что 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;
            }
        }
    }
}

Ответ 2

Если вам просто нужно что-то передать через 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?