webentwicklung-frage-antwort-db.com.de

renderpartial mit null model erhält den falschen Typ übergeben

Ich habe eine Seite:

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

Und darauf folgendes:

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

Hier ist das DTO-Objekt:

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

und hier ist der teil:

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

Wenn Model.Tasks nicht null ist, funktioniert alles einwandfrei. Aber wenn es null ist, bekomme ich:

Das in das Wörterbuch übergebene Modellelement ist vom Typ "DTOSearchResults", für dieses Wörterbuch ist jedoch ein Modellelement vom Typ "System.Collections.Generic.IEnumerable`1 [Task]" erforderlich.

Ich dachte, es muss nicht bekannt sein, welche Überladung verwendet werden soll, also habe ich dies (siehe unten) explizit angegeben, aber ich bekomme immer noch das gleiche Problem!

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

Ich weiß, dass ich das umgehen kann, indem ich auf null prüfe oder nicht einmal null übergebe, aber das ist nicht der Punkt. Warum passiert das?

192
Andrew Bullock

Andrew Ich denke, das Problem, das Sie bekommen, ist ein Ergebnis der RenderPartial-Methode, die das Modell des Aufrufs (Ansicht) für die Teilansicht verwendet, wenn das Modell, das Sie übergeben, null ist. Sie können dieses seltsame Verhalten umgehen, indem Sie Folgendes tun:

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

Hilft das?

340
meandmycode

@ myandmycodes Antwort ist gut, aber eine etwas kürzere wäre

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

Dies funktioniert, weil ViewDataDictionary das Modell enthält und ein Modell als Konstruktorparameter akzeptieren kann. Dies übergibt im Grunde genommen ein "gesamtes" View-Data-Dictionary, das natürlich nur das Möglich-Null-Modell enthält.

45
configurator

Wenn die Eigenschaft des übergebenen Modells null ist, wird MVC absichtlich auf das "übergeordnete" Modell zurückgesetzt. Anscheinend interpretiert die MVC-Engine einen Nullmodellwert als Absicht, den vorherigen zu verwenden.

Etwas mehr Details hier: ASP.NET MVC, stark typisierte Ansichten, teilweise Ansichtsparameterfehler

24
Zack

Wenn Sie Ihre vorherigen ViewData nicht in der Teilansicht verlieren möchten, können Sie Folgendes versuchen:

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

Eine Lösung wäre, einen HtmlHelper wie folgt zu erstellen:

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);
}

Das Partial<T>(...) stimmte mit dem Partial(...) überein, so bequem und ohne Mehrdeutigkeitsfehler beim Kompilieren.

Persönlich finde ich es schwierig, das Verhalten zu verstehen - scheint es mir schwer vorstellbar, dass dies eine Design-Wahl ist?

11
Colin Breame

Obwohl dies beantwortet wurde, bin ich auf dieses Problem gestoßen und habe beschlossen, es für mein Projekt zu lösen, anstatt es mit new ViewDataDictionary() zu umgehen.

Ich habe eine Reihe von Erweiterungsmethoden erstellt: https://github.com/q42jaap/PartialMagic.Mvc/blob/master/PartialMagic.Mvc/PartialExtensions.cs
Ich habe auch einige Methoden hinzugefügt, die das partielle nicht aufrufen, wenn das Modell null ist. Dadurch werden viele if-Anweisungen gespart.

Ich habe sie für Razor erstellt, aber einige von ihnen sollten auch mit Aspx-Ansichten funktionieren (die, die HelperResult verwenden, sind wahrscheinlich nicht kompatibel).

Die Erweiterungsmethoden sehen folgendermaßen aus:

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

Es gibt auch Methoden für IEnumerable<object> Modelle und die verworfenen Modelle können auch mit einem Razor Lambda aufgerufen werden, mit dem Sie das Teilergebnis mit etwas HTML umschließen können.

Fühlen Sie sich frei, sie zu verwenden, wenn Sie möchten.

11
Jaap

Mein Workaround dazu ist:


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