renderpartial con modelo nulo pasa el tipo incorrecto

Tengo una página:

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

Y sobre esto, lo siguiente:

  

Aquí está el objeto DTO:

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

y aquí está el parcial:

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

Cuando Model.Tasks no es nulo, todo funciona bien. Sin embargo, cuando es nulo, obtengo:

El elemento de modelo que se pasa al diccionario es del tipo ‘DTOSearchResults’, pero este diccionario requiere un elemento de modelo de tipo ‘System.Collections.Generic.IEnumerable`1 [Task]’.

Pensé que no debía saber qué sobrecarga utilizar, así que hice esto (ver más abajo) para ser explícito, ¡pero igual sigo teniendo el mismo problema!

  

Sé que puedo evitar esto comprobando nulo, o incluso sin pasar nulo, pero ese no es el punto. ¿Por qué está pasando esto?

Andrew: Creo que el problema que está obteniendo es el resultado del método RenderPartial que usa el modelo de llamada (vista) para la vista parcial cuando el modelo que pasa es nulo. Puede evitar este extraño comportamiento haciendo:

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

¿Eso ayuda?

La respuesta de @ myandmycode es buena, pero una más corta sería

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

Esto funciona porque ViewDataDictionary es lo que mantiene el modelo y puede aceptar un modelo como parámetro de constructor. Esto básicamente pasa un diccionario de datos de vista “completo”, que por supuesto solo contiene el modelo posiblemente nulo.

Parece que cuando la propiedad del Modelo que está ingresando es nula MVC intencionalmente revierte al Modelo “principal”. Aparentemente, el motor MVC interpreta un valor de modelo nulo como bash de usar el anterior.

Un poco más detalles aquí: ASP.NET MVC, vistas fuertemente tipadas, fallas en los parámetros de vista parcial

Si no quiere perder su ViewData anterior en la vista parcial, puede intentar:

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

Una solución sería crear un HtmlHelper como este:

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

El Partial(...) coincide antes del error Partial(...) tan conveniente y sin ambigüedad al comstackr.

Personalmente, me resulta difícil entender el comportamiento: parece difícil imaginar esto como una opción de diseño.

Aunque esto ha sido respondido, me encontré con esto y decidí que quería resolver este problema para mi proyecto en lugar de trabajar con el new ViewDataDictionary() .

Creé un conjunto de métodos de extensión: https://github.com/q42jaap/PartialMagic.Mvc/blob/master/PartialMagic.Mvc/PartialExtensions.cs
También agregué algunos métodos que no llaman al parcial si el modelo es nulo, esto ahorrará muchas declaraciones if.

Los creé para Razor, pero un par de ellos también deberían funcionar con vistas de estilo aspx (las que usan HelperResult probablemente no sean compatibles).

Los métodos de extensión se ven así:

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

También hay métodos para los IEnumerable y los descartados también se pueden llamar con un Razor lambda que le permite ajustar el resultado parcial con algún html.

Siéntase libre de usarlos si lo desea.

Mi solución a esto es:

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