El elemento de modelo que se pasa al diccionario es de tipo ... pero este diccionario requiere un elemento de modelo de tipo

84

Esta pregunta y la respuesta de la wiki de la comunidad se han agregado para ayudar a cerrar numerosas preguntas sin respuesta como se analiza en esta meta publicación .


Tengo algo de código y cuando se ejecuta, lanza una excepción que dice:

El elemento de modelo pasado al diccionario es de tipo Bar, pero este diccionario requiere un elemento de modelo de tipo Foo

¿Qué significa esto y cómo lo soluciono?

Comunidad
fuente
1
Recibí este error al usar en return Viewlugar de, return PartialViewpor lo que es algo para verificar
Richard Housham

Respuestas:

91

El error significa que está navegando a una vista cuyo modelo se declara como typeof Foo(al usar @model Foo), pero en realidad le pasó un modelo que es typeof Bar(tenga en cuenta que el término diccionario se usa porque un modelo se pasa a la vista a través de a ViewDataDictionary) .

El error puede deberse a

Pasar el modelo incorrecto de un método de controlador a una vista (o vista parcial)

Los ejemplos comunes incluyen el uso de una consulta que crea un objeto anónimo (o colección de objetos anónimos) y pasarlo a la vista

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

o pasar una colección de objetos a una vista que espera un solo objeto

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

El error se puede identificar fácilmente en tiempo de compilación declarando explícitamente el tipo de modelo en el controlador para que coincida con el modelo en la vista en lugar de usar var.

Pasar el modelo incorrecto de una vista a una vista parcial

Dado el siguiente modelo

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

y una vista principal declarada con @model Fooy una vista parcial declarada con @model Bar, luego

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

devolverá el modelo correcto a la vista principal. Sin embargo, se lanzará la excepción si la vista incluye

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

De forma predeterminada, el modelo que se pasa a la vista parcial es el modelo declarado en la vista principal y debe usar

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

para pasar la instancia de Bara la vista parcial. Tenga en cuenta también que si el valor de MyBares null(no se ha inicializado), de forma predeterminada se Foopasará al parcial, en cuyo caso, debe ser

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

Declarar un modelo en un diseño

Si un archivo de diseño incluye una declaración de modelo, todas las vistas que usan ese diseño deben declarar el mismo modelo o un modelo que se derive de ese modelo.

Si desea incluir el html para un modelo separado en un Diseño, en el Diseño, use @Html.Action(...)para llamar a un [ChildActionOnly]método, inicializa ese modelo y devuelve una vista parcial para él.

Stephen Muecke
fuente
26
+1 para "Tenga en cuenta también que si el valor de MyBar es nulo (no se ha inicializado), entonces, por defecto, Foo se pasará al parcial, en cuyo caso, debe ser". Nota muy importante.
Smix
Recibo el mismo error al tener una vista parcial dentro de un diseño, sin un tipo de modelo definido. La vista parcial se bloquea porque recibe el modelo de la página de índice cuando no hay ninguno definido ni necesario, y si configuro el modelo parcial en IndexModel, ¡entonces la propiedad ViewData es nula! ¿Cómo solucionar este escenario? Mover el parcial al diseño funciona, pero quiero entender cómo funciona.
Etienne Charland
Me encontré con el mismo error cuando mi vista parcial tenía "@page" en la parte superior sin "@model". eliminar "@page" resolvió el problema.
EKanadily
1
Si desea enviar intencionalmente un modelo nulo a la vista parcial cuando Model.MyBares nulo, puede hacer esto: @Html.Partial("_Bar", Model.MyBar, new System.Web.Mvc.ViewDataDictionary()) Fuente: https://stackoverflow.com/a/713921/4888725
Kirk Grover
6

Esta pregunta ya tiene una gran respuesta, pero me encontré con el mismo error, en un escenario diferente: mostrar un Listen un EditorTemplate .

Tengo un modelo como este:

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

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

Y esta es mi vista principal :

@model Foo

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

Y esta es mi Bar EditorTemplate ( Bar.cshtml )

@model List<Bar>

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

Y tengo este error:

El elemento de modelo pasado al diccionario es de tipo 'Bar', pero este diccionario requiere un elemento de modelo de tipo 'System.Collections.Generic.List`1 [Bar]


El motivo de este error es que EditorForya itera Listpor usted, por lo que si le pasa una colección, se mostrará la plantilla del editor una vez para cada elemento de la colección.

Así es como solucioné este problema:

Trajo los estilos fuera de la plantilla del editor y en la vista principal :

@model Foo

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

Y cambió el EditorTemplate ( Bar.cshtml ) a esto:

@model Bar

<label>@Model.BarName</label>
Hooman Bahreini
fuente
1
Genial, me salvaste después de media hora rascándome la cabeza. También funciona para ASP.NET Core 3.1 MVC.
Uwe Keim
5

Observe si la vista tiene el modelo requerido:

Ver

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

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

Controlador

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

En mi caso, uso una vista parcial pero se ejecuta en vistas normales

CelzioBR
fuente
1
¿Qué tiene esto que ver con la pregunta?
2
@StephenMuecke estos campeones: el elemento modelo que se pasó al diccionario es de tipo Bar, pero este diccionario requiere un elemento modelo del tipo Foo
CelzioBR