renderpartial с нулевой моделью передается неправильный тип
у меня есть страницы:
<%@ Page Inherits="System.Web.Mvc.View<DTOSearchResults>" %>
и на нем, следующие:
<% Html.RenderPartial("TaskList", Model.Tasks); %>
вот объект DTO:
public class DTOSearchResults
{
public string SearchTerm { get; set; }
public IEnumerable<Task> Tasks { get; set; }
и вот этот фрагмент:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Task>>" %>
Когда Модель.Задачи не нулевые, все работает нормально. Однако если его значение null, я получаю:
элемент модели, переданный в словарь, имеет тип 'DTOSearchResults', но этот словарь требует элементов модели типа - Система.Коллекции.Родовой.IEnumerable`1[Задача]'.
я решил, что он не должен знать, какую перегрузку использовать, поэтому я сделал это (см. ниже), чтобы быть явным, но я все равно получаю ту же проблему!
<% Html.RenderPartial("TaskList", (object)Model.Tasks, null); %>
Я знаю, что могу обойти это, проверяя null или даже не передавая null, но это не главное. Почему это происходит?
7 ответов:
Эндрю я думаю, что проблема, которую вы получаете, является результатом метода RenderPartial, использующего модель вызова (представления) для частичного представления, когда модель, которую вы передаете, равна нулю.. вы можете обойти это странное поведение, делая:
<% Html.RenderPartial("TaskList", Model.Tasks, new ViewDataDictionary()); %>
это поможет?
@myandmycode ответ хороший, но немного короче будет
<% Html.RenderPartial("TaskList", new ViewDataDictionary(Model.Tasks)); %>
это работает, потому что
ViewDataDictionary
- это то, что содержит модель, и она может принимать модель в качестве параметра конструктора. Это в основном передает" весь " словарь данных представления, который, конечно же, содержит только возможную нулевую модель.
похоже, что когда свойство модели, которую вы передаете, равно null, MVC намеренно возвращается к "родительской" модели. По-видимому, механизм MVC интерпретирует нулевое значение модели как намерение использовать предыдущее.
чуть подробнее здесь:ASP.NET MVC, строго типизированные представления, частичные параметры просмотра Глюк
Если вы не хотите потерять свои предыдущие ViewData в частичном представлении, вы можете попробовать:
<% Html.RenderPartial("TaskList", Model.Tasks, new ViewDataDictionary(ViewData){Model = null});%>
решение было бы создать HtmlHelper, как это:
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); }
The
Partial<T>(...)
совпадали доPartial(...)
так удобно и нет ошибки двусмысленности при компиляции.лично мне трудно понять поведение - трудно представить это как выбор дизайна?
хотя на это был дан ответ, я столкнулся с этим и решил, что хочу решить эту проблему для своего проекта вместо того, чтобы обойти ее с
new ViewDataDictionary()
.Я создал набор методов расширения : https://github.com/q42jaap/PartialMagic.Mvc/blob/master/PartialMagic.Mvc/PartialExtensions.cs
Я также добавил некоторые методы, которые не вызывают частичное, если модель равна нулю, это сэкономит много операторов if.Я создал их для бритвы, но некоторые из них также должны работать с представлениями стиля aspx (те, которые используют HelperResult, вероятно, несовместимы).
методы расширения выглядят так:
@* calls the partial with Model = null *@ @Html.PartialOrNull("PartialName", null) @* does not call the partial if the model is null *@ @Html.PartialOrDiscard("PartialName", null)
есть также методы для
IEnumerable<object>
модели и отбрасывать те, которые также могут быть вызваны с бритвой лямбда, которые позволяют обернуть частичный результат с некоторым html.не стесняйтесь использовать их, если хотите.