使用带有 Razor 视图引擎的 MVC 3。我有这个观点:
@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 })
在这两个视图中,当我调试它们并观看模型时,它似乎包含正确的对象。当我执行代码时,“var products =”行出现错误:
“对象”不包含“产品”的定义
谁能向我解释为什么我会收到这个错误?同样,当我在调试模式下观看模型对象时,它看起来还不错(有 2 个属性:产品和阈值)
您是否将匿名类的实例作为视图模型传递?我刚刚尝试过这个(CSHTML 中的动态视图模型)并且在使用匿名类时遇到了与您相同的错误,但是如果我创建了一个命名类,它就可以正常工作。我搜索过,但在任何地方都没有看到这个记录。
// error
return View(new { Foo = 1, Bar = "test" });
// worked
return View(new TestClass { Foo = 1, Bar = "test" });
编辑#1:
根据 David Ebbo,您不能将匿名类型传递给动态类型视图,因为匿名类型被编译为 internal
。由于 CSHTML 视图被编译成一个单独的程序集,它不能访问匿名类型的属性。
编辑#2:
David Ebbo 用这个澄清编辑了他的帖子:
注意(2011 年 12 月 22 日):现在 MVC 3 直接支持动态,下面的技术不再需要。这篇文章实际上是导致将该功能集成到 MVC 中的原因!
在 .NET 4.0 上,匿名类型可以很容易地转换为 ExpandoObjects,因此所有问题都可以通过转换本身的开销来解决。查看here
这与具有内部属性的匿名类型无关
完全可以将匿名类型从视图传递到局部视图
我今天遇到了同样的问题,这与传递匿名类型及其固有的 internal
属性的问题无关(直接)。
因此,关于 OPs 问题,@Lucas 的答案是无关紧要的——即使解决方法可行。
在 OPs 问题中,匿名类型从程序集 X 中的视图传递到程序集 X 中的部分,因此 David Ebbo 概述的匿名类型内部属性的问题无关紧要;为视图编译的类型、部分类型和匿名类型都包含在同一个程序集中。
那么是什么导致突然无法将匿名类型从视图传递到局部?
至少在 我的 情况下,我发现这是由于 SAME FOLDER 中的另一个视图指定了无法解析的模型类型。视图是在运行时编译的,因此在运行时编译视图失败也意味着编译动态类型失败并且部分将简单地接收 object
是有意义的。发生了什么并不是很明显,但在 OPs 的特定示例(和我的)中,这很可能是问题的原因。
有趣的是,如果模型类型正确但视图的另一部分未编译,则匿名类型不会以同样的方式受到影响。这必须归结为 Razor 如何分解视图组件部分的动态编译。
纠正有问题的视图后,要么重建整个解决方案,要么清理并重建项目,然后再检查它是否已修复。
为确保您不会再次被此问题所困扰,您可以通过将其添加到 csproj
文件来启用 Razor 视图的编译时编译:
<PropertyGroup>
<MvcBuildViews>true</MvcBuildViews>
</PropertyGroup>
在您的解决方案中的任何位置添加以下类(使用 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());
而不是在局部视图中使用 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>
我不确定您是否收到此错误,因为您没有实施解决方法。我在局部视图中遇到了同样的错误。解决方案只是清理构建并重建它。如果语法正确,代码应该可以工作,但剃须刀引擎可能无法正确更新代码更改。
我使用字典解决了这个问题。
@Html.Partial("_Partial", new Dictionary<string, string> { { "Key1", "Val1" }, { "Key2", "Val2" }, { "Key3", "Val3" } });
要使用 dynamic
类型,您需要引用 Microsoft.CSharp
程序集
return View(new { Foo = 1, Bar = "test" });
?因为我正在使用 MVC 4 并且仍然得到“对象不包含 Foo 的定义”ToExpando
旁边)