Подтвердить что ты не робот

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>>" %>

Когда Model.Tasks не является нулевым, все работает нормально. Однако когда его null я получаю:

Элемент модели, переданный в словарь, имеет тип "DTOSearchResults", но для этого словаря требуется элемент модели типа 'System.Collections.Generic.IEnumerable`1 [Задача]'.

Я понял, что не должен знать, какую перегрузку использовать, поэтому я сделал это (см. ниже), чтобы быть явным, но я все равно получаю ту же проблему!

<% Html.RenderPartial("TaskList", (object)Model.Tasks, null); %>

Я знаю, что могу обойти это, проверив нулевое значение или даже не пройдя нуль, но это не так. Почему это происходит?

4b9b3361

Ответ 1

Эндрю. Я думаю, что проблема, которую вы получаете, является результатом метода RenderPartial с использованием модели вызова (представления) в частичном представлении, когда модель, которую вы передаете, имеет значение null.. вы можете обойти это странное поведение, выполнив:

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

Помогает ли это?

Ответ 2

@myandmycode ответ хороший, но немного короче будет

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

Это работает, потому что ViewDataDictionary - это вещь, которая содержит модель, и она может принимать модель в качестве параметра конструктора. Это в основном передает "полный" словарь данных о представлении, который, конечно, содержит только возможную нулевую модель.

Ответ 3

Похоже, что когда свойство модели, которую вы передаете, является нулевым MVC, умышленно возвращается к "родительской" модели. По-видимому, MVC-механизм интерпретирует значение нулевой модели как намерение использовать предыдущий.

Немного подробнее здесь: ASP.NET MVC, сильно типизированные представления, частичные параметры представления сбой

Ответ 4

Если вы не хотите потерять свои предыдущие ViewData в частичном представлении, вы можете попробовать:

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

Ответ 5

Хотя на это был дан ответ, я столкнулся с этим и решил, что хочу решить эту проблему для моего проекта, вместо того, чтобы обойти его с помощью new ViewDataDictionary().

Я создал набор методов расширения: https://github.com/q42jaap/PartialMagic.Mvc/blob/master/PartialMagic.Mvc/PartialExtensions.cs
Я также добавил некоторые методы, которые не называют частичным, если модель равна null, это сэкономит много операторов if.

Я создал их для Razor, но некоторые из них также должны работать с представлениями стиля 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>, а отбрасываемые также можно вызвать с помощью лямбда Razor, которые позволяют обернуть частичный результат с помощью некоторого html.

Не стесняйтесь использовать их, если хотите.

Ответ 6

Решением было бы создать 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);
}

Partial<T>(...) соответствует Partial(...) так удобно и не допускает ошибки двусмысленности при компиляции.

Лично мне трудно понять поведение - кажется, сложно представить это как выбор дизайна?

Ответ 7

Мое обходное решение:


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