Je rencontre un problème plutôt frustrant. Mon site MVC fonctionne correctement dans la plupart des cas, mais génère une erreur au hasard (une erreur évidente pour l’utilisateur). Lorsque je vérifie les journaux, voici ce que je reçois:
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'.
Quelques instants plus tard, le même utilisateur peut cliquer sur Actualiser et la page se charge correctement. Je suis coincé. ; (
Mise à jour: trace de stack ajoutée
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, Ssortingng 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)
Voici un problème sur codeplex expliquant pourquoi cette erreur se produit.
Citation de http://web.archive.org/web/20131004122626/http://aspnet.codeplex.com/workitem/1795 puisque le lien d’origine est mort:
L’atsortingbut HandleError ne doit pas stocker les informations sur les exceptions dans ViewData
Lorsque l’atsortingbut
HandleError
gère une exception, il stocke les informations sur l’exception dansViewData
. Cela pose un problème lorsqueError.aspx
hérite desite.master
et que la classesite.master
est déclarée comme suit.public partial class Site : System.Web.Mvc.ViewMasterPage
{ }
SiteViewData
contient:public class SiteViewData { public Ssortingng Title { get; set; } }
Chaque classe
ViewData
page hérite de la classeSiteViewData
et ressemble à ceci:public class IndexViewData : SiteViewData { public Ssortingng Message { get; set; } public Ssortingng SupportedLanguages {get; set;} }
Cette approche permet d’écrire du code dans la page
Site.Master
comme suit
<%= Html.Encode(ViewData.Model.Title) %> Malheureusement, lorsqu’une exception est levée, le modèle a été remplacé par une instance de la classe
HandleErrorInfo
. Cela provoque uneInvalidOperationException
avec les informationsL’élément de modèle transmis au dictionnaire est de type
System.Web.Mvc.HandleErrorInfo
mais ce dictionnaire nécessite un élément de modèle de typeIgwt.Boh.Website.Web.Controllers.SiteViewData
.Est-il possible qu’une nouvelle propriété
ErrorData
soit ajoutée à la classeViewResult
pour stocker l’instance de la classeHandleErrorInfo
? De cette façon,ViewData
ne sera pas changé.Il est fort probable que toute exception levée dans l’action se produise après que les
IndexViewData
(etSiteViewData
) aient déjà été initialisées.Fermé le 27 janv. 2010 à 00:24 par
Ne réparera pas – voir les commentaires.
Les commentaires mentionnés avec “wontfix” proviennent d’un ancien membre de l’équipe Microsoft, avec leur suggestion de contourner le problème (en gras):
Au moment où l’atsortingbut [HandleError] est exécuté, nous avons perdu la référence à l’object ActionResult d’origine. Nous ne soaps même pas si vous aviez l’intention de montrer une vue de toute façon – peut-être avez-vous eu l’intention de redirect. La partie du pipeline (ViewResult) qui aurait été chargée de faire passer le modèle du contrôleur à la vue a disparu.
Si une exception se produit, tout modèle sur lequel l’application travaillait doit probablement être traité comme corrompu ou indisponible de toute façon. La meilleure pratique consiste à écrire votre vue Erreur de sorte que ni celle-ci ni ses dépendances (telles que sa page maître) n’exigent le modèle d’origine.
Pour résoudre ce problème, ma solution consiste à supprimer la directive @model en haut de la page de présentation, puis à effectuer des vérifications au cours desquelles je m’attendrais normalement à voir mon modèle basculer entre les différents modèles susceptibles d’être transmis, par exemple.
@if (Model is System.Web.Mvc.HandleErrorInfo) { Error } else if (Model.GetType() == typeof(MyApp.Models.BaseViewModel)) { @Model.PageTitleComplete }
Je viens de localiser un problème similaire dans mon application et je voulais décrire le correctif pour moi. Dans mon cas, je recevais l’exception suivante:
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'.
Et j’utilisais [HandleError] pour router les erreurs vers ~/Shared/Error.cshtml
Ce qui s’est passé [du moins dans mon cas] a été: ~/Shared/Error.cshtml
avait Layout = "~/Views/SiteLayout.cshtml";
pour vous assurer que la page d’erreur a été correctement stylée (comme le rest du site) sans dupliquer le layout / css includes.
~/Views/SiteLayout.cshtml
avait un partiel inclus: ~/Shared/LightboxLogin.cshtml
qui fournit une boîte à jour intégrée pour la connexion. ~/Shared/LightboxLogin.cshtml
comportait un autre partiel pour incorporer le formulaire de connexion réel: @Html.Partial("Login")
qui inclut ~/Shared/Login.cshtml
Il est utilisé pour la fonctionnalité de connexion au ~/Shared/Login.cshtml
site.
L’erreur étant due à la zone d’administration du site, le contrôleur était “Admin” et lorsqu’une erreur se produisait, Error.cshtml
était Error.cshtml
, ce qui incluait SiteLayout.cshtml
avec un modèle HandleErrorInfo
. Cela incluait LightboxLogin
, qui incluait ensuite Partial, Login
… mais il y avait une autre vue dans ~/Admin/Login.cshtml
qui était incluse à la place par @Html.Partial("Login")
.
Cette vue sur ~/Admin/Login.cshtml
avait ceci: @model Web.Models.Admin.Login
Ainsi, la leçon apprise ici est de faire attention à ne pas nommer les partiels que vous souhaitez inclure. Si ~/Shared/Login.cshtml
était ~/Shared/PublicLoginForm.cshtml
et que @Html.Partial("PublicLoginForm")
était utilisé, ce problème aurait été évité.
Sidenote: J’ai corrigé ceci comme si [parce que je ne voulais pas restructurer mes vues]:
@if (!(Model is HandleErrorInfo)) { @Html.Partial("LightboxLogin") }
Ce qui signifie que le partiel n’est pas inclus lorsque la mise en page est incluse dans une condition d’erreur.
J’ai rencontré cette erreur avec des vues fortement typées et je l’ai corrigée en définissant également RouteData.Values [“controller”] et “action” du contexte de requête d’origine pour correspondre aux noms de contrôleur de page d’erreur et d’action.
Si vous regardez ici, vous verrez une implémentation améliorée de HandleErrorAtsortingbute qui, outre le support JSON, vous indique également ce qui se passe dans la classe de base avec la vue des résultats.
https://www.dotnetsortingcks.com/learn/mvc/exception-or-error-handling-and-logging-in-mvc4
Si la construction de ViewResult ressemble à la logique utilisée par Microsoft, le problème pourrait être qu’il est uniquement capable de spécifier une nouvelle vue (condition d’erreur), pas le contrôleur ou l’action (car elle a été modifiée par rapport à la demande d’origine). C’est peut-être pour cette raison que les gestionnaires / framework MVC sont confondus avec les vues typées. Cela ressemble à un bug pour moi.
L’exemple ci-dessus n’inclut PAS ce correctif. Vous devez donc le modifier comme suit (les deux dernières lignes et le commentaire sont nouveaux):
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, eg to prevent error with typed views filterContext.RouteData.Values["controller"] = "MyError"; // MyErrorController.Index(HandleErrorInfo) filterContext.RouteData.Values["action"] = "Index";
Si vous ne le gérez pas dans un filtre / atsortingbut, il vous suffira de faire quelque chose comme les deux dernières lignes où vous traitez avec les données de routage. Par exemple, de nombreux exemples “OnError” construisent un contrôleur d’erreur puis appellent IContoller.Execute. Mais c’est une autre histoire.
Quoi qu’il en soit, si vous obtenez cette erreur, peu importe où vous la manipulez, il vous suffit de réinitialiser les noms “contrôleur” et “action” d’origine en fonction de ce que vous utilisez, ce qui peut le réparer également.