Element modelu przekazany do słownika jest typu .. ale ten słownik wymaga elementu modelu typu

87

To pytanie i odpowiedź wiki społeczności zostały dodane, aby pomóc w zamknięciu wielu pytań bez odpowiedzi, omówionych w tym meta poście .


Mam jakiś kod i kiedy się wykonuje, rzuca wyjątek mówiący:

Element modelu przekazany do słownika jest typu Bar, ale ten słownik wymaga elementu modelu typu Foo

Co to oznacza i jak to naprawić?

Społeczność
źródło
1
Otrzymałem ten błąd podczas używania return Viewzamiast, return PartialViewwięc to jest coś do sprawdzenia
Richard Housham,

Odpowiedzi:

94

Błąd oznacza, że ​​nawigujesz do widoku, którego model jest zadeklarowany jako typeof Foo(przy użyciu @model Foo), ale w rzeczywistości przekazałeś mu model, który jest typeof Bar(zwróć uwagę, że używany jest termin słownik, ponieważ model jest przekazywany do widoku za pośrednictwem a ViewDataDictionary) .

Błąd może być spowodowany przez

Przekazywanie niewłaściwego modelu z metody kontrolera do widoku (lub częściowego widoku)

Typowe przykłady obejmują użycie zapytania, które tworzy anonimowy obiekt (lub kolekcję obiektów anonimowych) i przekazanie go do widoku

var model = db.Foos.Select(x => new
{
    ID = x.ID,
    Name = x.Name
};
return View(model); // passes an anonymous object to a view declared with @model Foo

lub przekazanie kolekcji obiektów do widoku, który oczekuje pojedynczego obiektu

var model = db.Foos.Where(x => x.ID == id);
return View(model); // passes IEnumerable<Foo> to a view declared with @model Foo

Błąd można łatwo zidentyfikować w czasie kompilacji, jawnie deklarując typ modelu w kontrolerze, aby pasował do modelu w widoku, zamiast używać var.

Przekazywanie niewłaściwego modelu z widoku do częściowego widoku

Biorąc pod uwagę następujący model

public class Foo
{
    public Bar MyBar { get; set; }
}

a głównym widoku zadeklarowana @model Fooi częściowym widokiem zadeklarowana @model Bar, a następnie

Foo model = db.Foos.Where(x => x.ID == id).Include(x => x.Bar).FirstOrDefault();
return View(model);

zwróci prawidłowy model do widoku głównego. Jednak wyjątek zostanie zgłoszony, jeśli widok zawiera

@Html.Partial("_Bar") // or @{ Html.RenderPartial("_Bar"); }

Domyślnie model przekazany do widoku częściowego jest modelem zadeklarowanym w widoku głównym i należy go użyć

@Html.Partial("_Bar", Model.MyBar) // or @{ Html.RenderPartial("_Bar", Model.MyBar); }

przekazać instancję Bardo częściowego widoku. Zauważ również, że jeśli wartość MyBaris null(nie została zainicjowana), to domyślnie Foozostanie przekazana do częściowej, w takim przypadku musi być

@Html.Partial("_Bar", new Bar())

Deklarowanie modelu w układzie

Jeśli plik układu zawiera deklarację modelu, wszystkie widoki korzystające z tego układu muszą deklarować ten sam model lub model pochodzący z tego modelu.

Jeśli chcesz dołączyć @Html.Action(...)kod HTML dla oddzielnego modelu do układu, to w układzie użyj, aby wywołać [ChildActionOnly]metodę inicjuje ten model i zwraca dla niego częściowy widok.

Stephen Muecke
źródło
27
+1 dla "Zauważ również, że jeśli wartość MyBar jest zerowa (nie została zainicjowana), to domyślnie Foo zostanie przekazane do części, w którym to przypadku musi być". Bardzo ważna uwaga.
Smix
Otrzymuję ten sam błąd, mając widok częściowy w układzie, bez zdefiniowanego typu modelu. Widok częściowy ulega awarii, ponieważ otrzymuje model ze strony indeksu, gdy żaden nie jest zdefiniowany ani potrzebny, a jeśli ustawię model częściowy na IndexModel, właściwość ViewData ma wartość null! ?? Jak naprawić ten scenariusz? Przeniesienie części do układu działa, ale chcę zrozumieć, jak to działa.
Etienne Charland
Wystąpił ten sam błąd, gdy mój częściowy widok miał „@page” na górze bez „@model”. usunięcie „@page” rozwiązało problem.
EKanadily
1
Jeśli chcesz celowo wysłać zerowy model do częściowego widoku, gdy Model.MyBarjest zerowy, możesz to zrobić: @Html.Partial("_Bar", Model.MyBar, new System.Web.Mvc.ViewDataDictionary()) Źródło: https://stackoverflow.com/a/713921/4888725
Kirk Grover
@Smix to BARDZO pomocny komentarz. Właśnie wpadłem na to.
contactmatt
7

To pytanie ma już świetną odpowiedź, ale napotkałem ten sam błąd, w innym scenariuszu: wyświetlając Listw EditorTemplate .

Mam taki model:

public class Foo
{
    public string FooName { get; set; }
    public List<Bar> Bars { get; set; }
}

public class Bar
{
    public string BarName { get; set; }
}

I to jest mój główny pogląd :

@model Foo

@Html.TextBoxFor(m => m.Name, new { @class = "form-control" })  
@Html.EditorFor(m => m.Bars)

A to jest mój szablon Bar EditorTemplate ( Bar.cshtml )

@model List<Bar>

<div class="some-style">
    @foreach (var item in Model)
    {
        <label>@item.BarName</label>
    }
</div>

I dostałem ten błąd:

Element modelu przekazany do słownika jest typu „Bar”, ale ten słownik wymaga elementu modelu typu „System.Collections.Generic.List” 1 [Bar]


Przyczyną tego błędu jest to, że EditorForjuż wykonuje iterację Listdla Ciebie, więc jeśli przekażesz do niej kolekcję, wyświetli szablon edytora raz dla każdego elementu w kolekcji.

Oto jak naprawiłem ten problem:

Przeniesiono style poza szablon edytora i do głównego widoku :

@model Foo

@Html.TextBoxFor(m => m.Name, new { @class = "form-control" })  
<div class="some-style">
    @Html.EditorFor(m => m.Bars)
</div>

I zmieniłem EditorTemplate ( Bar.cshtml ) na to:

@model Bar

<label>@Model.BarName</label>
Hooman Bahreini
źródło
1
Wspaniale, właśnie uratowałeś mnie po pół godzinie drapania się po głowie. Działa również dla ASP.NET Core 3.1 MVC.
Uwe Keim
6

Obserwuj, czy widok ma wymagany model:

Widok

@model IEnumerable<WFAccess.Models.ViewModels.SiteViewModel>

<div class="row">
    <table class="table table-striped table-hover table-width-custom">
        <thead>
            <tr>
....

Kontroler

[HttpGet]
public ActionResult ListItems()
{
    SiteStore site = new SiteStore();
    site.GetSites();

    IEnumerable<SiteViewModel> sites =
        site.SitesList.Select(s => new SiteViewModel
        {
            Id = s.Id,
            Type = s.Type
        });

    return PartialView("_ListItems", sites);
}

W moim przypadku używam częściowego widoku, ale działa w normalnych widokach

CelzioBR
źródło
1
Co to ma wspólnego z pytaniem?
2
@StephenMuecke this champs - Model przekazany do słownika jest typu Bar, ale ten słownik wymaga elementu modelu typu Foo
CelzioBR