Modello dinamico MVC Razor, "oggetto" non contiene la definizione di "PropertyName"


106

Utilizzo di MVC 3 con il motore di visualizzazione Razor. Ho questa vista:

@model dynamic
@{
    var products = (List<ListItemBaseModel>)Model.Products;
    var threshold = (int)(Model.Threshold ?? 1);
    var id = Guid.NewGuid().ToString();
}

Viene chiamato da un'altra vista utilizzando questo codice:

@Html.Partial("PartialViewName", new { Products = Model, Threshold = 5 })

In entrambe le viste, quando eseguo il debug e guardo Model, sembra che contenga l'oggetto corretto. Quando eseguo il codice ottengo un errore sulla riga "var products =" che dice:

"oggetto" non contiene una definizione per "Prodotti"

Qualcuno può spiegarmi perché ottengo quell'errore? Ancora una volta, quando guardo l'oggetto Model in modalità di debug sembra a posto (con 2 proprietà: Products e Threshold)


Risposte:


150

Stai passando un'istanza di una classe anonima come modello di visualizzazione? Ho appena provato questo (modello di visualizzazione dinamica in CSHTML) e ho ricevuto lo stesso errore del tuo quando si utilizza una classe anonima, ma ha funzionato bene se ho creato una classe con nome. Ho cercato ma non l'ho visto documentato da nessuna parte.

// error
return View(new { Foo = 1, Bar = "test" });

// worked
return View(new TestClass { Foo = 1, Bar = "test" });

MODIFICA # 1:

Secondo David Ebbo , non è possibile passare un tipo anonimo in una vista tipizzata dinamicamente perché i tipi anonimi sono compilati come internal. Poiché la vista CSHTML è compilata in un assembly separato, non può accedere alle proprietà del tipo anonimo.

MODIFICA # 2:

David Ebbo ha modificato il suo post con questa precisazione:

Nota (22/12/2011): ora che MVC 3 ha il supporto diretto per la dinamica, la tecnica seguente non è più necessaria. Questo post è in effetti ciò che ha portato a integrare la funzionalità in MVC!


1
La modifica è piacevole da sapere. Ho appena avuto lo stesso problema e non ho capito il WTF lì. Grazie per la spiegazione.
Yanick Rochon

18
EDIT # 2 suggerisce che ora (MVC> 3) è possibile fare la riga contrassegnata con "errore"? return View(new { Foo = 1, Bar = "test" });? Perché sto usando MVC 4 e continuo a ricevere "l'oggetto non contiene una definizione per Foo"
sport

@sports anche me ... hai trovato una soluzione? (accanto a ToExpandoquello)
Alex

2
Quindi ora nel 2018 utilizzando ASP.NET Core 2.1 e le visualizzazioni Razor, trovo che l'errore nella domanda originale mi stia ancora mordendo. Quindi non so di cosa si parli su MVC 3 che risolve questo problema, dal momento che sembra ancora rotto.
Andrew Arnott

41

Su .NET 4.0 i tipi anonimi possono essere facilmente convertiti in ExpandoObjects e quindi tutti i problemi vengono risolti con l'overhead della conversione stessa. Controlla qui


Prego. Forse questo spinge M $ per rendere i tipi anonimi più utilizzabili
Adaptabi

Questo vale per i parziali però? Ho ricevuto un errore che i Partials non possono essere inviati dinamicamente ...
John Bubriski

1
Quali parziali? Puoi fornire un esempio?
Adaptabi

27

Questo non ha nulla a che fare con i tipi anonimi che hanno proprietà interne

È perfettamente possibile passare tipi anonimi da una vista a una vista parziale

Oggi ho riscontrato lo stesso problema e non aveva nulla (direttamente) a che fare con il problema del passaggio di tipi anonimi e delle loro internalproprietà intrinseche .

In quanto tale, in relazione alla domanda dei PO, la risposta di @Lucas è irrilevante, anche se la soluzione alternativa funzionerà .

Nella domanda OPs, un tipo anonimo viene passato da una vista nell'assembly X a una parziale nell'assembly X , quindi il problema che David Ebbo ha delineato delle proprietà interne per i tipi anonimi non ha conseguenze; i tipi compilati per la vista, il tipo parziale e il tipo anonimo sono tutti contenuti nello stesso assembly .

Allora cosa sta causando l'improvviso mancato passaggio di un tipo anonimo da una vista a una parziale?

Almeno nella mia situazione, ho scoperto che era dovuto alla presenza di un'altra vista nella STESSA CARTELLA che specifica un tipo di modello che non può essere risolto . Le viste vengono compilate in fase di esecuzione, quindi avrebbe senso in quanto un errore in fase di esecuzione nella compilazione delle viste significherebbe anche un errore nella compilazione dei tipi dinamici e il parziale riceverebbe semplicemente un object. Non è immediatamente ovvio cosa sta succedendo, ma nell'esempio specifico dei PO (e nel mio) questa è più che probabile la causa del problema.

È interessante notare che se il tipo di modello è corretto ma un'altra parte della vista non viene compilata, i tipi anonimi non vengono influenzati allo stesso modo. Questo deve dipendere dal modo in cui Razor suddivide la compilazione dinamica delle parti componenti della vista.

Dopo aver corretto la vista offensiva, ricostruire l'intera soluzione o pulire e ricostruire il progetto prima di verificare se è stato risolto.

Per assicurarti di non essere più sorpreso da questo, puoi abilitare la compilazione in fase di compilazione delle tue viste Razor aggiungendo questo al tuo csprojfile:

<PropertyGroup>
    <MvcBuildViews>true</MvcBuildViews>
</PropertyGroup>

2
Questo ha risolto il mio problema: l'uso di "@model dynamic" inizialmente sembrava la soluzione giusta, ma in realtà mi stava portando sulla strada sbagliata.
crimbo

Ho pulito la soluzione, ricostruita e l'errore è sparito .. 121 voti positivi fuori posto.
maxbeaudoin

Ho aggiornato la mia risposta per riflettere il supporto di MVC per i modelli di visualizzazione dinamica da MVC 3.
Lucas

Abilitare la compilazione delle viste di tanto in tanto è sempre utile per una base di codice enorme. Rivela tutti i tipi di problemi, errori di battitura, errori con T4MVC grazie alla digitazione forte introdotta ecc.
Denis The Menace

Oh, giusto: ho appena notato che stiamo parlando di passare da una vista a una parziale qui. Non da un controller a una vista, che è il mio problema.
mwardm

9

Aggiungi la seguente classe ovunque nella tua soluzione (usa lo spazio dei nomi di sistema, quindi è pronto per l'uso senza dover aggiungere alcun riferimento) -

    namespace System
    {
        public static class ExpandoHelper
        {
            public static ExpandoObject ToExpando(this object anonymousObject)
            {
                IDictionary<string, object> anonymousDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(anonymousObject);
                IDictionary<string, object> expando = new ExpandoObject();
                foreach (var item in anonymousDictionary)
                    expando.Add(item);
                return (ExpandoObject)expando;
            }

        }
    }

Quando invii il modello alla vista, convertilo in Expando:

    return View(new {x=4, y=6}.ToExpando());

1
mi sembra un sovraccarico inutile creare prima un oggetto dinamico e poi un ExpandoObject ... Basta creare invece ExpandoObject ..
Baz1nga

@ Baz1nga Non puoi fare ... new Expando () {prop = value, ...}, il che lo rende problematico. Sto usando JObject di Json.Net per un utilizzo simile.
Tracker1

3
Sembra sbagliato avere HtmlHelper lì dentro ... public static ExpandoObject ToExpando (this object o) {IDictionary <string, object> expando = new ExpandoObject (); foreach (var propertyInfo in o.GetType (). GetProperties ()) {expando.Add (new KeyValuePair <string, object> (propertyInfo.Name, propertyInfo.GetValue (o, index: null))); } return (ExpandoObject) expando; }
erlando

6

Invece di usare il dynamictipo di modello nella vista parziale.

È possibile chiamare gli attributi dell'oggetto anonimo utilizzando @ViewData.Eval("foo")invece di @Model.foo.

Quindi puoi rimuovere @Model dynamicdalla visualizzazione.

Di recente mi sono imbattuto in questo problema passando alcuni attributi tra le visualizzazioni per l'integrazione dei commenti sociali di Facebook. Codice di esempio:

Html.RenderPartial(@"Layouts/Partials/_Comments", new {currentUrl = Model.CurrentPage.GetAbsoluteUrl(), commentCount = 5 });

Quindi a mio avviso ho appena avuto questo div:

<div class="fb-comments" data-href="@ViewData.Eval("currentUrl")" data-numposts="@ViewData.Eval("commentCount")" data-width="100%"></div>

0

non sono sicuro che tu riceva questo errore perché non stai implementando il work-around. ho ricevuto lo stesso errore in una vista parziale. la soluzione era solo pulire la build e ricostruirla. se la sintassi è corretta, il codice dovrebbe funzionare, ma il motore Razor potrebbe non aggiornare correttamente le modifiche al codice.


0

Ho aggirato questo problema utilizzando un dizionario.

 @Html.Partial("_Partial", new Dictionary<string, string> { { "Key1", "Val1" }, { "Key2", "Val2" }, { "Key3", "Val3" } });

-6

Per usare il dynamictipo è necessario fare riferimento Microsoft.CSharpall'assembly

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.