Аргх! Почему система.Сеть.В MVC.HandleErrorInfo передается в мои представления?

Я испытываю довольно неприятную проблему. Мой сайт MVC работает нормально по большей части, но случайным образом выдает ошибку (которая показывает дружественную ошибку пользователю). Когда я проверяю журналы, это то, что я получаю:

System.InvalidOperationException: The model item passed into the dictionary is of type 'System.Web.Mvc.HandleErrorInfo' but this dictionary requires a model item of type 'BaseViewData'.

мгновения спустя тот же пользователь может нажать "Обновить", и страница загрузится нормально. Я застрял. ;(

Update: добавлена трассировка стека

System.Web.HttpUnhandledException: Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.InvalidOperationException: The model item passed into the dictionary is of type 'System.Web.Mvc.HandleErrorInfo' but this dictionary requires a model item of type 'BaseViewData'.
   at System.Web.Mvc.ViewDataDictionary`1.SetModel(Object value)
   at System.Web.Mvc.ViewDataDictionary..ctor(ViewDataDictionary dictionary)
   at System.Web.Mvc.HtmlHelper`1..ctor(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection)
   at System.Web.Mvc.ViewMasterPage`1.get_Html()
   at ASP.views_shared_site_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer)
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
   at System.Web.UI.Control.Render(HtmlTextWriter writer)
   at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
   at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
   at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.UI.Control.RenderChildren(HtmlTextWriter writer)
   at System.Web.UI.Page.Render(HtmlTextWriter writer)
   at System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer)
   at System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter)
   at System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter)
   at System.Web.UI.Control.RenderControl(HtmlTextWriter writer)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
   --- End of inner exception stack trace ---
   at System.Web.UI.Page.HandleError(Exception e)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
   at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
   at System.Web.UI.Page.ProcessRequest()
   at System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext context)
   at System.Web.UI.Page.ProcessRequest(HttpContext context)
   at ASP.views_shared_error_aspx.ProcessRequest(HttpContext context)
   at System.Web.Mvc.ViewPage.RenderView(ViewContext viewContext)
   at System.Web.Mvc.WebFormView.RenderViewPage(ViewContext context, ViewPage page)
   at System.Web.Mvc.WebFormView.Render(ViewContext viewContext, TextWriter writer)
   at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
   at System.Web.Mvc.Controller.ExecuteCore()
   at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext)
   at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext)
   at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext)
   at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext)
   at System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

4 ответов


здесь на страницы CodePlex объясняя, почему возникает эта ошибка.

цитата http://web.archive.org/web/20131004122626/http://aspnet.codeplex.com/workitem/1795 поскольку оригинальная ссылка мертва:

атрибут HandleError не должен хранить информацию об исключении в ViewData

когда HandleError атрибут обрабатывает исключение, он хранит информацию об исключении в ViewData. Это проблема, когда Error.aspx наследует от site.master и site.master класс объявляется следующим образом.

public partial class Site : System.Web.Mvc.ViewMasterPage<SiteViewData>
{
}

SiteViewData содержит:

public class SiteViewData 
{
  public String Title { get; set; } 
}

каждой страницы ViewData класс наследуется от SiteViewData класса и выглядит примерно так

public class IndexViewData : SiteViewData
{
  public String Message { get; set; }
  public String SupportedLanguages {get; set;}
}

этот подход позволяет писать код в Site.Master страница следующим образом

<title><%= Html.Encode(ViewData.Model.Title) %></title>

к сожалению, когда возникает исключение, модель была заменено экземпляром HandleErrorInfo класса. Это вызывает InvalidOperationException чтобы быть брошенным с информацией

элемент модели, переданный в словарь, имеет тип System.Web.Mvc.HandleErrorInfo но этот словарь требует элементов модели типа Igwt.Boh.Website.Web.Controllers.SiteViewData.

возможно ли новое ErrorData свойство, которое будет добавлено в ViewResult класс для хранения экземпляра класса? Сюда ViewData не изменяется.

шансы довольно хорошо, что любое исключение, брошенное в действие, произойдет после IndexViewDataSiteViewData) свойства уже инициализированы.

закрыто 27 января 2010 года в 12:24 по

не будет исправлено - см. комментарии.


комментарии, упомянутые с "wontfix", от бывшего члена команды Microsoft, вместе с их предложением для работы вокруг него (выделено жирным шрифтом):

к моменту атрибута [HandleError] исполняет, мы потеряли ссылка на исходный объект ActionResult. Мы даже не знаем, вы все равно собирались показать вид - может быть, вы собирались перенаправить. Часть конвейера (ViewResult), которая была бы ответственным за передачу модели от контроллера к представлению является ушедший.

если возникает исключение, любая модель, над которой работает приложение вероятно, следует рассматривать как коррумпированные или недоступные в любом случае. лучшие практика нужно написать свой вид ошибки так, чтобы ни он, ни его зависимости (например, его главная страница) требуют оригинала модель.


мое решение для решения проблемы-удалить директиву @model в верхней части страницы макета, а затем выполнить некоторые проверки, где я обычно ожидаю увидеть мою модель для переключения между различными моделями, которые могут быть переданы, например

@if (Model is System.Web.Mvc.HandleErrorInfo)
{
    <title>Error</title>
}
else if (Model.GetType() == typeof(MyApp.Models.BaseViewModel))
{
    <meta name="description" content="@Model.PageMetaDescription">
    <title>@Model.PageTitleComplete</title>
}

я только что отследил аналогичную проблему в своем приложении и хотел описать исправление для меня. В моем случае я получал следующее исключение:

System.InvalidOperationException: The model item passed into the dictionary is of 
type 'System.Web.Mvc.HandleErrorInfo', but this dictionary requires a model item of
type 'Web.Models.Admin.Login'.

и я использовал [HandleError] для маршрута ошибок ~/Shared/Error.cshtml

что случилось [по крайней мере в моем случае] было: ~/Shared/Error.cshtml had Layout = "~/Views/SiteLayout.cshtml"; чтобы убедиться, что страница ошибки была стилизована правильно (как и остальная часть сайта) без дублирования макета/css включает.

~/Views/SiteLayout.cshtml было частично включено:~/Shared/LightboxLogin.cshtml который обеспечивает встроенный лайтбокс для входа. ~/Shared/LightboxLogin.cshtml еще частично для размещения фактическая форма входа: @Html.Partial("Login"), которая включает ~/Shared/Login.cshtml Это используется для функций входа в систему на интерфейсе Сайта.

поскольку ошибка была вызвана в административной области сайта, контроллер был "Admin", и когда произошла ошибка,Error.cshtml был вызван, в который вошли SiteLayout.cshtml С HandleErrorInfo модель. Это, в свою очередь, входит LightboxLogin, который затем включены частичные,Login... но в ~/Admin/Login.cshtml, который был включен .

этот вид на ~/Admin/Login.cshtml было так: @model Web.Models.Admin.Login

Итак, урок, извлеченный здесь, будьте осторожны с наименованием ваших партиалов, которые вы хотите включить. Если ~/Shared/Login.cshtml был ~/Shared/PublicLoginForm.cshtml и @Html.Partial("PublicLoginForm") было б тогда этой проблемы можно было бы избежать.

Sidenote: я исправил это так [как я не хотел реструктурировать мой просмотров]:

@if (!(Model is HandleErrorInfo))
{
   @Html.Partial("LightboxLogin")
}

что означает, что частичное не включено, когда макет включен в условие ошибки.


У меня была эта ошибка со строго типизированными представлениями и исправила ее, также установив RouteData исходного контекста запроса.Значения ["controller"] и" action", чтобы соответствовать контроллеру страницы ошибок и именам действий.

Если вы посмотрите здесь, вы увидите расширенную реализацию HandleErrorAttribute, которая помимо поддержки JSON также показывает вам, что происходит в базовом классе с результатом вид.

https://www.dotnettricks.com/learn/mvc/exception-or-error-handling-and-logging-in-mvc4

Если конструкция ViewResult здесь похожа на логику, используемую Microsoft, то проблема может заключаться в том, что она может указать только новое (условие ошибки) представление, а не контроллер или действие (поскольку оно изменилось с исходного запроса). Возможно, именно поэтому фреймворк / обработчики MVC путаются с типизированными представлениями. Похоже, ошибка мне.

приведенный выше пример не включает это исправление, поэтому вам придется отредактировать его следующим образом (последние две строки и комментарий являются новыми):

var model = new HandleErrorInfo(httpError, controllerName, actionName);
filterContext.Result = new ViewResult
{
    ViewName = View,
    MasterName = Master,
    ViewData = new ViewDataDictionary(model),
    TempData = filterContext.Controller.TempData
};

// Correct routing data when required, e.g. to prevent error with typed views
filterContext.RouteData.Values["controller"] = "MyError";  // MyErrorController.Index(HandleErrorInfo)
filterContext.RouteData.Values["action"] = "Index";

Если вы не обрабатываете его в фильтре / атрибуте, вам нужно только сделать что-то вроде последних двух строк, где вы имеете дело с данными маршрутизации, например, многие примеры "OnError" создают контроллер ошибок, а затем вызывают IContoller.Выполнять. Но это уже другая история.

в любом случае, если вы получите эту ошибку, где бы вы ни находились обрабатывая ошибку, просто сбросьте исходное имя" контроллер "и" действие " на то, что вы используете, и это может исправить его для вас.