啊!为什么 System.Web.Mvc.HandleErrorInfo 会传递到我的视图?

发布于 2024-08-16 16:28:25 字数 4056 浏览 5 评论 0原文

我遇到了一个相当令人沮丧的问题。我的 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'.

不久之后,同一个用户可以点击刷新并且页面加载正常。我被困住了。 ;(

更新:添加堆栈跟踪

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)

I'm experiencing a rather frustrating problem. My MVC site runs fine for the most part, but randomly throws an error (which shows a friendly error to the user). When I check the logs, this is what I get:

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'.

Moments later, the same user could hit refresh and the page loads fine. I'm stuck. ;(

Update: added stack trace

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

亢潮 2024-08-23 16:28:25

这里codeplex 解释了发生该错误的原因。

引用自 http://web.archive.org /web/20131004122626/http://aspnet.codeplex.com/workitem/1795 因为原始链接已失效:

HandleError 属性不应在 ViewData 中存储异常信息

HandleError属性处理异常时,它会将异常信息存储在ViewData中。当 Error.aspx 继承自 site.master 并且 site.master 类声明如下时,就会出现问题。

公共分部类 Site : System.Web.Mvc.ViewMasterPage
{
}

SiteViewData 包含:

公共类SiteViewData 
{
  公共字符串标题{获取;放; } 
}

每个页面ViewData类都继承自SiteViewData类,看起来像这样

公共类 IndexViewData : SiteViewData
{
  公共字符串消息{获取;放; }
  公共字符串SupportedLanguages {get;放;}
}

这种方法允许人们在 Site.Master 页面中编写代码,如下所示

<标题><%= Html.Encode(ViewData.Model.Title) %>

不幸的是,当抛出异常时,模型已被替换为 HandleErrorInfo 类的实例。这会导致抛出 InvalidOperationException 以及该信息

传递到字典中的模型项的类型为System.Web.Mvc.HandleErrorInfo,但此字典需要类型为Igwt.Boh.Website.Web.Controllers.SiteViewData的模型项.

是否可以将新的 ErrorData 属性添加到 ViewResult 类来存储 HandleErrorInfo 类的实例?这样 ViewData 就不会改变。

在初始化 IndexViewData(和 SiteViewData)属性之后,操作中引发的任何异常很有可能会发生。

截止时间为 2010 年 1 月 27 日中午 12:24

无法修复 - 请参阅评论。


提到“wontfix”的评论来自 Microsoft 团队的前成员,以及他们解决该问题的建议(粗体):

当 [HandleError] 属性执行时,我们已经丢失了
对原始 ActionResult 对象的引用。我们甚至不知道是否
无论如何,您打算显示视图 - 也许您打算重定向。
本来应该是的管道部分(ViewResult)
负责将模型从控制器传递到视图的是
走了。

如果发生异常,应用程序正在处理的任何模型
无论如何应该被视为损坏或不可用。 最好的
实践是编写您的错误视图,这样它或
它的依赖项(例如它的母版页)需要原始的
模型。

Here is an issue on codeplex explaining why that error occurs.

Quote from http://web.archive.org/web/20131004122626/http://aspnet.codeplex.com/workitem/1795 since original link is dead:

HandleError Attribute should not store exception information in ViewData

When the HandleError attribute handles an exception, it stores the exception information in the ViewData. This is a problem when the Error.aspx inherits from the site.master and the site.master class is declared as follows.

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

SiteViewData contains:

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

Each page ViewData class inherits from the SiteViewData class and looks something like this

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

This approach allows one to write code in the Site.Master page as follows

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

Unfortunately, when an exception is thrown, the model has been replaced with an instance of the HandleErrorInfo class. This causes an InvalidOperationException to be thrown with the information

The model item passed into the dictionary is of type System.Web.Mvc.HandleErrorInfo but this dictionary requires a model item of type Igwt.Boh.Website.Web.Controllers.SiteViewData.

Is it possible for a new ErrorData property to be added to the ViewResult class to store the instance of the HandleErrorInfo class instead? This way the ViewData does not get changed.

Chances are pretty good that any exception thrown in the action will occur after the IndexViewData (and SiteViewData) properties have already been initialized.

Closed Jan 27, 2010 at 12:24 AM by

Won't fix - see comments.


The comments mentioned with "wontfix" are from a former member of the Microsoft team, along with their suggestion for working around it (bolded):

By the time the [HandleError] attribute executes, we've lost the
reference to the original ActionResult object. We don't even know if
you intended to show a view anyway - maybe you intended to redirect.
The part of the pipeline (the ViewResult) that would have been
responsible for passing the model from the controller to the view is
gone.

If an exception occurs, any model the application was working on
should probably be treated as corrupt or unavailable anyway. The best
practice would be to write your Error view such that neither it nor
its dependencies (such as its master page) requires the original
model.

晨曦慕雪 2024-08-23 16:28:25

我处理该问题的解决方案是删除布局页面顶部的 @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>
}

My solution for dealing with the problem is to remove the @model directive at the top of the layout page and then do some checks where I'd normally expect to see my model to switch between the different models that might get passed in e.g.

@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>
}
再见回来 2024-08-23 16:28:25

我刚刚在我的应用程序中发现了类似的问题,并想为我描述修复方法。
就我而言,我遇到了以下异常:

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.cshtmlLayout = "~/Views/SiteLayout.cshtml"; 以确保错误页面的样式正确(就像网站的其他部分一样) )而不重复布局/css 包含。

~/Views/SiteLayout.cshtml 包含部分内容:~/Shared/LightboxLogin.cshtml,它为登录提供了一个内联灯箱。
~/Shared/LightboxLogin.cshtml 有一个进一步的部分来嵌入实际的登录表单:@Html.Partial("Login") 其中包括 ~/Shared/登录.cshtml
这用于网站前端的登录功能。

由于错误是在站点的 Admin 区域引起的,因此控制器是“Admin”,并且当发生错误时,会调用 Error.cshtml,其中包括 SiteLayout.cshtml使用 HandleErrorInfo 模型。
这又包括 LightboxLogin,然后又包括部分、Login...但是~/Admin/ 中有另一个视图Login.cshtml@Html.Partial("Login") 包含。

~/Admin/Login.cshtml 的这个视图有这样的内容:@model Web.Models.Admin.Login

因此,这里学到的教训是要小心你的部分命名您想要包含的内容。如果 ~/Shared/Login.cshtml~/Shared/PublicLoginForm.cshtml 并使用 @Html.Partial("PublicLoginForm") 那么这个问题本来是可以避免的。

旁注:我像这样修复了这个问题[因为我不想重组我的视图]:

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

这意味着当布局包含在错误条件中时,不包含部分。

I've just tracked down a similar issue in my app and wanted to describe the fix for me.
In my case, I was getting the following exception:

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'.

And I was using [HandleError] to route errors to ~/Shared/Error.cshtml

What happened [at least in my case] was:
~/Shared/Error.cshtml had Layout = "~/Views/SiteLayout.cshtml"; to ensure that the Error page was styled correctly (like the rest of the site) without duplicating the layout/css includes.

~/Views/SiteLayout.cshtml had a partial included: ~/Shared/LightboxLogin.cshtml which provides an inline lightbox for the login.
~/Shared/LightboxLogin.cshtml had a further partial to embed the actual login form: @Html.Partial("Login") which includes ~/Shared/Login.cshtml
This is used for the login functionality on the front-end of the site.

Because the error was caused in the Admin area of the site, the controller was "Admin" and when an error occurred, Error.cshtml was invoked, which included SiteLayout.cshtml with a HandleErrorInfo model.
This in turn included LightboxLogin, which then included the Partial, Login... but there was another view in ~/Admin/Login.cshtml which was included by the @Html.Partial("Login") instead.

This view at ~/Admin/Login.cshtml had this: @model Web.Models.Admin.Login

So, lesson learned here is be careful of your naming of your partials that you want to include. If ~/Shared/Login.cshtml was ~/Shared/PublicLoginForm.cshtml and @Html.Partial("PublicLoginForm") was used then this issue would have been avoided.

Sidenote: I fixed this like so [as I didn't want to restructure my views]:

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

Which means the Partial is not included when the layout is included in an Error condition.

北风几吹夏 2024-08-23 16:28:25

我在强类型视图中遇到了此错误,并通过设置原始请求上下文的 RouteData.Values[“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.Execute。但那是另一个故事了。

无论如何,如果您收到此错误,无论您在何处处理错误,只需将原始的“控制器”和“操作”名称重置为您正在使用的任何名称,它也可能会为您修复它。

I had this error with strongly typed views and fixed it by also setting the original request context's RouteData.Values["controller"] and "action" to match the error page controller and action names.

If you look here you will see an enhanced HandleErrorAttribute implementation which besides the JSON support also shows you what is going on in the base class with the result view.

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

If the ViewResult construction here is anything like the logic used by Microsoft, then the issue could be that it is only able to specify a new (error condition) view, not the controller or action (as it has changed from the original request). Perhaps that's why the MVC framework/handlers are getting confused with typed views. It seems like a bug to me.

The example above does NOT include this fix, so you'll have to edit it as follows (last two lines and comment are new):

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";

If you're not handling it in a filter/attribute then you only need do something like the last two lines where you are dealing with the routing data, e.g. many "OnError" examples construct an error controller then call IContoller.Execute. But that's another story.

Anyway, if you get this error, wherever you are handling the error, just reset the original "controller" and "action" name to whatever you are using and it may fix it for you too.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文