asp.net mvc - pass - renderpartial con modelo nulo se pasa el tipo incorrecto
pass data to partialview (7)
Tengo una página:
<%@ Page Inherits="System.Web.Mvc.View<DTOSearchResults>" %>
Y en ella, lo siguiente:
<% Html.RenderPartial("TaskList", Model.Tasks); %>
Aquí está el objeto DTO:
public class DTOSearchResults
{
public string SearchTerm { get; set; }
public IEnumerable<Task> Tasks { get; set; }
Y aquí está el parcial:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Task>>" %>
Cuando Model.Tasks no es nulo, todo funciona bien. Sin embargo, cuando es nulo me sale:
El elemento del modelo que se pasa al diccionario es del tipo ''DTOSearchResults'' pero este diccionario requiere un elemento del modelo ''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 todavía tengo el mismo problema!
<% Html.RenderPartial("TaskList", (object)Model.Tasks, null); %>
Sé que puedo solucionar este problema comprobando si hay un valor nulo, o incluso un paso nulo, pero ese no es el punto. ¿Por qué está pasando esto?
Andrew Pienso que el problema que está obteniendo es el resultado del método RenderPartial que usa el modelo de la llamada (vista) para la vista parcial cuando el modelo que pasa es nulo ... puede solucionar este extraño comportamiento haciendo:
<% Html.RenderPartial("TaskList", Model.Tasks, new ViewDataDictionary()); %>
¿Eso ayuda?
Aunque esto ha sido respondido, encontré esto y decidí que quería resolver este problema para mi proyecto en lugar de solucionarlo 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 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<object>
y los descartados también se pueden llamar con un lambda Razor que le permite envolver el resultado parcial con algunos html.
Siéntase libre de usarlos si lo desea.
La respuesta de @myandmycode es buena, pero una más breve sería
<% Html.RenderPartial("TaskList", new ViewDataDictionary(Model.Tasks)); %>
Esto funciona porque ViewDataDictionary
es lo que contiene el modelo y puede aceptar un modelo como parámetro de constructor. Básicamente, esto pasa un diccionario de datos de vista "completo", que por supuesto solo contiene el modelo posiblemente nulo.
Mi solución a esto es:
<% Html.RenderPartial("TaskList", Model.Tasks ?? new List()); %>
Parece que cuando la propiedad del Modelo que está pasando es nula, MVC vuelve intencionalmente al Modelo "padre". Al parecer, el motor MVC interpreta un valor de modelo nulo como intento de usar el anterior.
Un poco más de detalles aquí: ASP.NET MVC, vistas fuertemente tipificadas, parámetros parciales en la vista.
Si no desea perder sus ViewData anteriores en la vista parcial, podría 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<T>(this HtmlHelper htmlHelper, string partialViewName, T model)
{
ViewDataDictionary viewData = new ViewDataDictionary(htmlHelper.ViewData)
{
Model = model
};
return PartialExtensions.Partial(htmlHelper, partialViewName, model, viewData);
}
El Partial<T>(...)
coincidió antes que el Partial(...)
por lo que es conveniente y no hay error de ambigüedad al compilar.
Personalmente, me resulta difícil entender el comportamiento. ¿Parece difícil imaginarlo como una opción de diseño?