Model dynamiczny MVC Razor, „obiekt” nie zawiera definicji „PropertyName”


106

Używanie MVC 3 z silnikiem widoku Razor. Mam ten widok:

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

Jest wywoływana z innego widoku przy użyciu tego kodu:

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

W obu widokach, kiedy debuguję je i oglądam Model, wydaje się, że zawiera on poprawny obiekt. Kiedy wykonuję kod, w wierszu „var products =” pojawia się błąd o treści:

„obiekt” nie zawiera definicji „produktów”

Czy ktoś może mi wyjaśnić, dlaczego otrzymuję ten błąd? Ponownie, kiedy oglądam obiekt Model w trybie debugowania, wygląda dobrze (ma 2 właściwości: produkty i próg)


Odpowiedzi:


150

Czy jako model widoku przekazujesz wystąpienie klasy anonimowej? Właśnie wypróbowałem to (model widoku dynamicznego w CSHTML) i otrzymałem ten sam błąd, co twój, gdy używam klasy anonimowej, ale działało dobrze, gdy utworzyłem nazwaną klasę. Szukałem, ale nigdzie nie widziałem tego udokumentowanego.

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

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

EDYCJA # 1:

Według Davida Ebbo nie można przekazać typu anonimowego do widoku z typami dynamicznymi, ponieważ typy anonimowe są kompilowane jako internal. Ponieważ widok CSHTML jest kompilowany do oddzielnego zestawu, nie może uzyskać dostępu do właściwości typu anonimowego.

EDYCJA # 2:

David Ebbo zredagował swój post z tym wyjaśnieniem:

Uwaga (22.12.2011): teraz, gdy MVC 3 ma bezpośrednie wsparcie dla dynamiki, poniższa technika nie jest już potrzebna. To właśnie ten post doprowadził do integracji tej funkcji z MVC!


1
Zmiana jest miło wiedzieć. Po prostu miałem ten sam problem i nie rozumiałem tam WTF. Dziękuję za wyjaśnienie.
— Yanick Rochon

18
EDYCJA # 2 sugeruje, że teraz (MVC> 3) jest możliwe zrobienie linii oznaczonej jako "błąd"? return View(new { Foo = 1, Bar = "test" });? Ponieważ używam MVC 4 i nadal otrzymuję komunikat „obiekt nie zawiera definicji dla Foo”
— sport,

@sports me too ... czy znalazłeś obejście? (obok ToExpandojednego)
— Alex

2
Tak więc teraz, w 2018 roku, używając widoków ASP.NET Core 2.1 i Razor, stwierdzam, że błąd w oryginalnym pytaniu nadal mnie gryzie. Więc nie wiem, o co chodzi w tej rozmowie o naprawieniu MVC 3, ponieważ nadal wydaje się zepsuty.
— Andrew Arnott,

41

Na .NET 4.0 typy anonimowe można łatwo przekonwertować na ExpandoObjects, a zatem wszystkie problemy są naprawiane z narzutem samej konwersji. Sprawdź tutaj


Zapraszamy. Może to wyrzuca M $, aby anonimowe typy były bardziej użyteczne
— Adaptabi

Czy dotyczy to jednak częściowych? Pojawił się błąd, że Partials nie mogą być dynamicznie wysyłane ...
— John Bubriski

1
Jakie częściowe? Czy możesz podać przykład?
— Adaptabi

27

Nie ma to nic wspólnego z typami anonimowymi, które mają właściwości wewnętrzne

Jest całkowicie możliwe przekazanie anonimowych typów z widoku do częściowego widoku

Napotkałem dziś ten sam problem i nie miał on (bezpośrednio) nic wspólnego z problemem przekazywania anonimowych typów i ich nieodłącznych internalwłaściwości.

W związku z tym, w odniesieniu do pytania PO, odpowiedź @Lucas jest nieistotna - mimo że obejście zadziała .

W pytaniu PO anonimowy typ jest przekazywany z widoku w zestawie X do częściowego w zestawie X , dlatego problem, który przedstawił David Ebbo, dotyczący właściwości wewnętrznych dla typów anonimowych, nie ma żadnego znaczenia; typy skompilowane dla widoku, typ częściowy i anonimowy są zawarte w tym samym zestawie .

Więc co powoduje nagłe niepowodzenie w przekazaniu anonimowego typu z widoku do częściowego?

Przynajmniej w mojej sytuacji odkryłem, że było to spowodowane innym widokiem w TYM SAMYM FOLDERZE, który określa typ modelu, którego nie można rozwiązać . Widoki są kompilowane w czasie wykonywania, więc miałoby to sens, ponieważ kompilacja widoków w czasie wykonywania oznaczałaby również niepowodzenie kompilacji typów dynamicznych, a częściowa po prostu otrzymałaby plik object. Nie jest od razu oczywiste, co się dzieje, ale w konkretnym przykładzie PO (i moim) jest to najprawdopodobniej przyczyną problemu.

Warto zauważyć, że jeśli typ modelu jest poprawny, ale inna część widoku nie kompiluje się, to nie wpływa to w ten sam sposób na typy anonimowe. Musi to wynikać z tego, jak Razor rozbija dynamiczną kompilację części składowych widoku.

Po poprawieniu nieprawidłowego widoku odbuduj całe rozwiązanie lub wyczyść i odbuduj projekt przed sprawdzeniem, czy został naprawiony.

Aby upewnić się, że nie zostaniesz ponownie zaskoczony, możesz włączyć kompilację w czasie kompilacji widoków Razor, dodając to do swojego csprojpliku:

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

2
To rozwiązało mój problem - użycie „@model dynamic” początkowo wydawało się dobrym rozwiązaniem, ale w rzeczywistości prowadziło mnie na złą ścieżkę.
— crimbo

Wyczyściłem rozwiązanie, odbudowałem i błąd zniknął .. 121 głosów nie trafiło.
— maxbeaudoin

Zaktualizowałem moją odpowiedź, aby odzwierciedlić obsługę MVC dla modeli widoku dynamicznego od czasu MVC 3.
— Lucas

Włączanie kompilacji widoków od czasu do czasu jest zawsze przydatne w przypadku dużej bazy kodu. Ujawnia wszelkiego rodzaju problemy, literówki, błędy z T4MVC dzięki wprowadzonemu silnemu pisaniu itp.
— Denis The Menace

Och, racja: właśnie zauważyłem, że mówimy tutaj o przejściu od widoku do częściowego. Nie od kontrolera do widoku, co jest moim problemem.
— mwardm

9

Dodaj następującą klasę w dowolnym miejscu w swoim rozwiązaniu (użyj przestrzeni nazw System, aby była gotowa do użycia bez konieczności dodawania żadnych odwołań) -

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

        }
    }

Kiedy wysyłasz model do widoku, przekonwertuj go na Expando:

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

1
Wygląda jak unnecssary napowietrznych do mnie, aby utworzyć obiekt dynamiczny, a potem utworzyć ExpandoObject ... Wystarczy stworzyć ExpandoObject zamiast ..
— Baz1nga

@ Baz1nga Nie możesz zrobić ... new Expando () {prop = value, ...}, co sprawia, że ​​jest to problematyczne. Używam JObject Json.Net do podobnego użytku.
— Tracker1,

3
Źle jest mieć tam HtmlHelpera ... public static ExpandoObject ToExpando (ten obiekt 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

Zamiast używać dynamictypu Model w widoku częściowym.

Możesz wywołać anonimowe atrybuty obiektu za pomocą @ViewData.Eval("foo")zamiast @Model.foo.

Następnie możesz usunąć @Model dynamicz widoku.

Niedawno natknąłem się na ten problem podczas przekazywania niektórych atrybutów między widokami w celu integracji komentarzy społecznościowych na Facebooku. Przykładowy kod:

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

Wtedy moim zdaniem po prostu miałem ten div:

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

0

nie jestem pewien, czy otrzymujesz ten błąd, ponieważ nie wdrażasz obejścia. mam ten sam błąd w częściowym widoku. rozwiązaniem było po prostu wyczyszczenie kompilacji i odbudowanie jej. jeśli składnia jest poprawna, kod powinien działać, ale silnik maszynki do golenia może nie aktualizować poprawnie kodu.


0

Obejrzałem ten problem za pomocą słownika.

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

-6

Aby użyć dynamictypu, musisz odwołać się do Microsoft.CSharpzestawu

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.