Model dinamis MVC Razor, 'object' tidak mengandung definisi untuk 'PropertyName'

106

Menggunakan MVC 3 dengan mesin Razor view. Saya memiliki Pandangan ini:

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

Ini dipanggil dari tampilan lain menggunakan kode ini:

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

Di kedua Tampilan, saat saya men-debug dan menonton Model, tampaknya berisi objek yang benar. Ketika saya menjalankan kode, saya mendapatkan kesalahan pada baris "var products =" yang mengatakan:

'object' tidak mengandung definisi untuk 'Products'

Adakah yang bisa menjelaskan kepada saya mengapa saya mendapatkan kesalahan itu? Sekali lagi, ketika saya melihat objek Model dalam mode debugging, itu terlihat baik-baik saja (memiliki 2 properti: Produk dan Ambang)

Ruud van Falier
sumber

Jawaban:

150

Apakah Anda meneruskan sebuah instance dari kelas anonim sebagai model tampilan? Saya baru saja mencoba ini (model tampilan dinamis dalam CSHTML) dan mendapatkan kesalahan yang sama seperti saat Anda menggunakan kelas anonim, tetapi berfungsi dengan baik jika saya membuat kelas bernama. Saya mencari tetapi belum melihat ini didokumentasikan di mana pun.

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

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

EDIT # 1:

Menurut David Ebbo , Anda tidak dapat meneruskan tipe anonim ke tampilan yang diketik secara dinamis karena tipe anonim dikompilasi sebagai internal. Karena tampilan CSHTML dikompilasi menjadi rakitan terpisah, itu tidak dapat mengakses properti tipe anonim.

EDIT # 2:

David Ebbo telah mengedit postingannya dengan klarifikasi ini:

Catatan (22/12/2011): sekarang MVC 3 memiliki dukungan langsung untuk dinamika, teknik di bawah ini tidak lagi diperlukan. Postingan ini sebenarnya yang menyebabkan pengintegrasian fitur ke dalam MVC!

Lucas
sumber
1
Hasil editnya bagus untuk diketahui. Saya baru saja mengalami masalah yang sama dan tidak memahami WTF di sana. Terima kasih untuk penjelasannya.
Yanick Rochon
18
EDIT # 2 menyarankan bahwa sekarang (MVC> 3) dimungkinkan untuk melakukan baris ke yang ditandai dengan "error"? return View(new { Foo = 1, Bar = "test" });? Karena saya menggunakan MVC 4 dan masih mendapatkan "objek tidak mengandung definisi untuk Foo"
olahraga
@ Olahraga saya juga ... apakah Anda menemukan solusi? (di samping ToExpandosatu)
Alex
2
Jadi sekarang di tahun 2018 menggunakan ASP.NET Core 2.1 dan tampilan Razor, saya menemukan kesalahan pada pertanyaan asli masih menggigit saya. Jadi saya tidak tahu pembicaraan apa tentang perbaikan MVC 3 ini, karena sepertinya masih rusak.
Andrew Arnott
41

Pada .NET 4.0 Jenis anonim dapat dengan mudah diubah ke ExpandoObjects dan dengan demikian semua masalah diperbaiki dengan overhead dari konversi itu sendiri. Lihat di sini

Adaptabi
sumber
Sama sama. Mungkin ini menarik M $ untuk membuat jenis anonim lebih bermanfaat
Adaptabi
Apakah ini berlaku untuk Partial? Saya mendapat pesan kesalahan bahwa Partial tidak dapat dikirim secara dinamis ...
John Bubriski
1
Parsial apa? Bisakah Anda memberikan contoh?
Adaptabi
27

Ini tidak ada hubungannya dengan tipe anonim yang memiliki properti internal

Sangat mungkin untuk meneruskan tipe anonim dari tampilan ke tampilan parsial

Saya mengalami masalah yang sama hari ini dan itu tidak ada (secara langsung) ada hubungannya dengan masalah meneruskan tipe anonim dan internalproperti yang melekat padanya .

Karenanya, terkait pertanyaan OP, jawaban dari @Lucas tidak relevan - meskipun solusi tersebut akan berhasil .

Dalam pertanyaan OP, tipe anonim sedang diteruskan dari tampilan di perakitan X ke sebagian di perakitan X , oleh karena itu masalah yang dijelaskan oleh David Ebbo tentang properti yang bersifat internal untuk jenis anonim bukanlah konsekuensi; tipe yang dikompilasi untuk tampilan, tipe parsial dan anonim semuanya terkandung dalam rakitan yang sama .

Jadi apa yang menyebabkan kegagalan mendadak untuk meneruskan jenis anonim dari tampilan ke sebagian?

Setidaknya dalam situasi saya , saya menemukan bahwa itu karena memiliki tampilan lain di FOLDER SAMA yang menentukan jenis model yang tidak dapat diselesaikan . Tampilan dikompilasi pada waktu proses, sehingga akan masuk akal karena kegagalan pada waktu proses untuk mengompilasi tampilan juga berarti kegagalan untuk mengompilasi jenis dinamis dan sebagian hanya akan menerima object. Tidak segera jelas apa yang sedang terjadi, tetapi dalam contoh spesifik OP (dan milik saya) kemungkinan besar ini adalah penyebab masalahnya.

Menarik untuk dicatat bahwa jika tipe model benar tetapi bagian lain dari tampilan tidak dikompilasi maka tipe anonim tidak terpengaruh dengan cara yang sama. Ini pasti tentang bagaimana Razor memecah kompilasi dinamis dari bagian komponen tampilan.

Setelah Anda memperbaiki tampilan yang melanggar, buat ulang seluruh solusi atau bersihkan dan buat ulang proyek sebelum memeriksa untuk melihat apakah sudah diperbaiki.

Untuk memastikan Anda tidak ketahuan lagi, Anda dapat mengaktifkan kompilasi waktu kompilasi tampilan Razor Anda dengan menambahkan ini ke csprojfile Anda :

<PropertyGroup>
    <MvcBuildViews>true</MvcBuildViews>
</PropertyGroup>
joshcomley
sumber
2
Ini memperbaiki masalah saya - menggunakan "@model dynamic" pada awalnya tampak seperti perbaikan yang benar, tetapi ternyata membawa saya ke jalan yang salah.
crimbo
Saya membersihkan solusinya, membangunnya kembali dan kesalahannya hilang .. 121 suara salah taruh.
maxbeaudoin
Saya telah memperbarui jawaban saya untuk mencerminkan dukungan MVC untuk model tampilan dinamis sejak MVC 3.
Lucas
Mengaktifkan kompilasi tampilan dari waktu ke waktu selalu berguna untuk basis kode yang sangat besar. Mengungkap semua jenis masalah, kesalahan ketik, kesalahan dengan T4MVC berkat ketikan yang kuat yang diperkenalkan, dll.
Denis The Menace
Oh, benar: Saya baru saja memperhatikan bahwa kita sedang berbicara tentang berpindah dari satu pandangan ke sebagian di sini. Bukan dari pengontrol ke tampilan, yang merupakan masalah saya.
mwardm
9

Tambahkan kelas berikut di mana saja dalam solusi Anda (gunakan namespace Sistem, sehingga siap digunakan tanpa harus menambahkan referensi apa pun) -

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

        }
    }

Saat Anda mengirim model ke tampilan, konversikan ke Expando:

    return View(new {x=4, y=6}.ToExpando());
Segev -CJ- Shmueli
sumber
1
Sepertinya overhead yang tidak perlu bagi saya untuk membuat objek dinamis terlebih dahulu dan kemudian membuat ExpandoObject ... Cukup buat ExpandoObject saja ..
Baz1nga
@ Baz1nga Anda tidak dapat melakukan ... new Expando () {prop = value, ...}, yang membuatnya bermasalah. Saya menggunakan JObject Json.Net untuk penggunaan serupa.
Pelacak1
3
Rasanya salah memiliki HtmlHelper di sana ... public static ExpandoObject ToExpando (objek ini o) {IDictionary <string, object> expando = new ExpandoObject (); foreach (var propertyInfo di o.GetType (). GetProperties ()) {expando.Add (new KeyValuePair <string, object> (propertyInfo.Name, propertyInfo.GetValue (o, index: null))); } kembali (ExpandoObject) expando; }
erlando
6

Alih-alih menggunakan dynamicjenis Model dalam tampilan parsial.

Anda dapat memanggil atribut objek anonim menggunakan @ViewData.Eval("foo")bukan @Model.foo.

Kemudian Anda dapat menghapus @Model dynamicdari tampilan.

Saya menemukan masalah ini baru-baru ini ketika menyampaikan beberapa atribut di antara tampilan untuk Integrasi Komentar Sosial Facebook. Kode contoh:

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

Kemudian dalam pandangan saya, saya baru saja memiliki div ini:

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

Saya tidak yakin Anda mendapatkan kesalahan ini karena Anda tidak menerapkan penyelesaiannya. saya mendapat kesalahan yang sama dalam tampilan parsial. solusinya adalah hanya membersihkan build dan membangunnya kembali. jika sintaksnya benar, kode seharusnya berfungsi, tetapi razor engine mungkin tidak memperbarui perubahan kode dengan benar.

goran
sumber
0

Saya mengatasi masalah ini dengan menggunakan Kamus.

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

Untuk menggunakan dynamictipe Anda perlu referensi Microsoft.CSharpperakitan

the_joric
sumber