renderpartial avec le modèle null obtient le mauvais type

J’ai une page:

<%@ Page Inherits="System.Web.Mvc.View" %> 

Et sur ce qui suit:

  

Voici l’object DTO:

 public class DTOSearchResults { public ssortingng SearchTerm { get; set; } public IEnumerable Tasks { get; set; } 

et voici le partiel:

 <%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable>" %> 

Lorsque Model.Tasks n’est pas nul, tout fonctionne bien. Cependant quand sa null je reçois:

L’élément de modèle passé dans le dictionnaire est de type ‘DTOSearchResults’, mais ce dictionnaire requirejs un élément de modèle de type ‘System.Collections.Generic.IEnumerable`1 [Task]’.

J’ai pensé qu’il ne fallait pas savoir quelle surcharge utiliser, alors je l’ai fait (voir ci-dessous) pour être explicite, mais j’ai toujours le même problème!

  

Je sais que je peux contourner ce problème en vérifiant la valeur null, ou même ne pas dépasser null, mais ce n’est pas le point. Pourquoi cela arrive-t-il?

Andrew Je pense que le problème que vous rencontrez est un résultat de la méthode RenderPartial qui utilise le modèle de l’appel (view) à la vue partielle lorsque le modèle que vous passez est null. Vous pouvez contourner ce comportement étrange en faisant:

 <% Html.RenderPartial("TaskList", Model.Tasks, new ViewDataDictionary()); %> 

Est ce que ça aide?

La réponse de @ myandmycode est bonne, mais une réponse légèrement plus courte serait

 <% Html.RenderPartial("TaskList", new ViewDataDictionary(Model.Tasks)); %> 

Cela fonctionne car le ViewDataDictionary est l’élément qui contient le modèle et il peut accepter un modèle en tant que paramètre constructeur. Cela passe essentiellement par un dictionnaire de données de vue “entier”, qui ne contient bien sûr que le modèle éventuellement nul.

Il semble que lorsque la propriété du modèle que vous transmettez est nulle, MVC retourne intentionnellement au modèle “parent”. Apparemment, le moteur MVC interprète une valeur de modèle null comme intention d’utiliser la précédente.

Un peu plus de détails ici: ASP.NET MVC, vues fortement typées, parameters de vue partiels

Si vous ne voulez pas perdre votre ViewData précédent dans la vue partielle, vous pouvez essayer:

 <% Html.RenderPartial("TaskList", Model.Tasks, new ViewDataDictionary(ViewData){Model = null});%> 

Une solution serait de créer un HtmlHelper comme ceci:

 public static MvcHtmlSsortingng Partial(this HtmlHelper htmlHelper, ssortingng partialViewName, T model) { ViewDataDictionary viewData = new ViewDataDictionary(htmlHelper.ViewData) { Model = model }; return PartialExtensions.Partial(htmlHelper, partialViewName, model, viewData); } 

Le Partial(...) correspond avant le Partial(...) si pratique et aucune erreur d’ambiguïté lors de la compilation.

Personnellement, je trouve difficile de comprendre le comportement – semble difficile d’imaginer cela comme un choix de conception?

Bien que cela ait été répondu, j’ai couru à travers cela et j’ai décidé de résoudre ce problème pour mon projet au lieu de le contourner avec le new ViewDataDictionary() .

J’ai créé un ensemble de méthodes d’extension: https://github.com/q42jaap/PartialMagic.Mvc/blob/master/PartialMagic.Mvc/PartialExtensions.cs
J’ai également ajouté des méthodes qui n’appellent pas le partiel si le modèle est nul, cela sauvera beaucoup d’instructions if.

Je les ai créés pour Razor, mais quelques-uns devraient également fonctionner avec des vues de style aspx (celles qui utilisent HelperResult ne sont probablement pas compatibles).

Les méthodes d’extension ressemblent à ceci:

 @* calls the partial with Model = null *@ @Html.PartialOrNull("PartialName", null) @* does not call the partial if the model is null *@ @Html.PartialOrDiscard("PartialName", null) 

Il existe également des méthodes pour les modèles IEnumerable et les méthodes IEnumerable peuvent également être appelées avec un lambda Razor qui vous permet d’envelopper le résultat partiel avec du HTML.

N’hésitez pas à les utiliser si vous le souhaitez.

Ma solution à ce problème est la suivante:

<% Html.RenderPartial("TaskList", Model.Tasks ?? new List()); %>
<% Html.RenderPartial("TaskList", Model.Tasks ?? new List()); %>