MVC Razor动态模型,“object”不包含“PropertyName”的定义。

107

使用MVC 3和Razor视图引擎。我有以下视图:

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

使用以下代码从另一个视图调用它:

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

在这两个视图中,当我进行调试并查看Model时,它似乎包含了正确的对象。
但是当我执行代码时,在var products =这一行会出现错误:

'object' does not contain a definition for 'Products'

为什么我会看到这个错误?
当我在调试模式下查看Model对象时,它看起来都没问题(拥有2个属性:Products和Threshold)


8个回答

153

我刚刚尝试了在CSHTML中使用动态视图模型,当使用匿名类时,我得到了与您相同的错误,但是如果我创建一个命名类,则可以正常工作。我搜索过,但没有在任何地方找到记录。

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

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

David Ebbo 澄清了您不能将匿名类型传递到动态类型的视图中,因为匿名类型被编译为 internal。由于 CSHTML 视图被编译为单独的程序集,所以它无法访问匿名类型的属性。根据这篇论坛帖子,David Ebbo 在 2011 年 12 月 22 日澄清道,MVC 3 现在直接支持动态类型。


1
修改很好了解。我刚遇到了同样的问题,不明白那里出了什么问题。感谢您的解释。 - Yanick Rochon
18
EDIT #2 表明现在(MVC > 3)是否可能将代码行 return View(new { Foo = 1, Bar = "test" }); 标记为“错误”?因为我正在使用 MVC 4,但仍然遇到“对象不包含 Foo 的定义”的问题。 - sports
@ sports 我也是... 你找到了解决方法吗?(除了 ToExpando 之外) - Alex from Jitbit
2
所以现在在2018年,使用ASP.NET Core 2.1和Razor视图,我发现原问题中的错误仍然困扰着我。所以我不知道关于MVC 3修复这个问题的谈论是怎么回事,因为它似乎仍然存在问题。 - Andrew Arnott

41

在.NET 4.0中,匿名类型可以轻松地转换为ExpandoObjects,从而解决了所有与转换本身相关的问题。请查看这里


不客气。也许这会促使微软使匿名类型更易用。 - DATEx2
这是否适用于局部变量?我收到了一个错误,指出局部变量无法进行动态调度... - John B
1
什么是partials?你能提供一个例子吗? - DATEx2

30

这与匿名类型具有内部属性无关

从视图到局部视图传递匿名类型是完全可行的

今天我遇到了同样的问题,但它与传递匿名类型及其固有的internal属性无直接关系。

因此,在与OP提出的问题相关的情况下,@Lucas给出的答案是不相关的 - 即使绕过方法可以起作用

在OP的问题中,一个匿名类型被传递从程序集X中的视图到程序集X中的局部视图,因此David Ebbo概述的匿名类型属性为内部的问题并不重要;视图、局部和匿名类型编译的类型都包含在同一程序集中

那么是什么导致了无法将匿名类型从视图传递到局部视图?

至少在我的情况下,我发现这是由于同一文件夹中有另一个视图指定了无法解析的模型类型。视图在运行时编译,因此如果编译视图失败,则动态类型也会编译失败,局部视图只能接收一个object。这一点并不明显,但在OP的具体示例(以及我的情况)中,这很可能是问题的原因。

有趣的是,如果模型类型正确,但视图的其他部分无法编译,则匿名类型不会受到相同的影响。这必须归因于Razor如何分解视图组件部分的动态编译。

一旦您纠正了有问题的视图,要么重建整个解决方案,要么清理并重新构建项目,然后再检查是否已经修复。

为了确保不再受到此类问题的困扰,您可以通过将以下内容添加到csproj文件中来启用Razor视图的编译时间编译:

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

2
这解决了我的问题 - 最初使用“@model dynamic”似乎是正确的修复方法,但实际上却让我走了错误的道路。 - crimbo
我清理了解决方案,重新构建了它,错误已经消失了。121个赞被错放了位置。 - maxbeaudoin
哦,对了:我刚注意到我们在这里讨论的是从视图传递到部分视图。而不是从控制器传递到视图,这就是我的问题所在。 - mwardm
你如何确定哪个视图有编译错误?我在csproj文件中添加了MvcBuildViews属性,但没有额外的信息出现。我将所有其他视图物理移动到一个外部文件夹中。即使我只有这一个视图和一个局部视图在解决方案中,错误仍然会抛出。 - Jeff
这个解决方案对我有帮助。我也遇到了同样的问题。在修复视图中的问题后得到了解决。 - user3404686
显示剩余2条评论

10

在你的解决方案中任何位置添加以下类(使用System命名空间,这样它就可以在不必添加任何引用的情况下立即使用) -

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

        }
    }

当您将模型发送到视图时,请将其转换为 Expando:

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

1
对我来说,先创建一个动态对象然后再创建ExpandoObject似乎是一种不必要的开销... 直接创建ExpandoObject即可。 - Baz1nga
@Baz1nga 你不能使用 ... new Expando() { prop=value, ... } 这种方式,这会带来问题。我使用 Json.Net 的 JObject 来实现类似的用法。 - Tracker1
3
在这里使用HtmlHelper感觉不太对...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; } (注:该代码片段将一个对象转换为ExpandoObject类型) - erlando

9

在局部视图中,不要使用 dynamic 模型类型。

你可以使用 @ViewData.Eval("foo") 调用匿名对象属性,而不是使用 @Model.foo

然后,你可以从视图中删除 @Model dynamic

我最近在为 Facebook 社会化评论集成在视图之间传递某些属性时遇到了这个问题。示例代码:

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

在我看来,我只有这个 div:

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

0

我不确定你是否因为没有实现解决方法而遇到了这个错误。我在一个局部视图中也遇到了同样的错误。解决方案就是清理构建并重新构建它。如果语法正确,代码应该可以工作,但Razor引擎可能无法正确更新代码更改。


0
我通过使用字典解决了这个问题。
 @Html.Partial("_Partial", new Dictionary<string, string> { { "Key1", "Val1" }, { "Key2", "Val2" }, { "Key3", "Val3" } });

-6

如果要使用 dynamic 类型,您需要引用 Microsoft.CSharp 程序集。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接