这是我的控制器代码:
IQueryable<Foo> foos = dbContext.Foos.Where(...);
return View(foos);
这个剃刀代码(cshtml)可以很好:
@model IQueryable<Foo>
@{
IQueryable<Foo> foos = Model;
var projected = foos.Select(e => new
{
fooId = e.FooId,
bar = new
{
barId = e.Foo.BarId
}
}).ToList();
}
@foreach (var x in projected)
{
<span>@x.fooId</span><br />
}
但是这个剃刀代码(cshtml)不起作用,几乎是一样的东西!:
@model IQueryable<Foo>
@{
IQueryable<Foo> foos = Model;
var projected = foos.Selected(Foo.Projection()).ToList()
}
@foreach (var x in projected)
{
<span>@x.fooId</span><br />
}
Foo.Projection()
是一种静态方法,我重复使用了很多:
public static Expression<Func<Foo, dynamic>> Projection()
{
return e => new
{
fooId = e.FooId,
bar = new
{
barId = e.Foo.BarId
}
}
}
我得到了那个着名的错误:'object' does not contain definition for 'fooId'
,这里讨论的是MVC Razor dynamic model, 'object' does not contain definition for 'PropertyName' - 但这些答案都没有帮助我。
接受的答案说:&#34; 现在MVC 3直接支持动态,下面的技术已不再需要&#34;,所以我也尝试返回预计的{ {1}}到视图(&#34;准备使用,无需投影&#34;)并且它也没有工作(获得相同的错误)。这是该尝试的代码:
控制器代码:
List<dynamic>
查看代码:
List<dynamic> foos = dbContext.Foos.Select(Foo.Projection()).ToList();
return View(foos);
编辑:使用调试器,我能够检查(在抛出异常之后)项目确实具有 @model dynamic
etc.
(在示例代码中项目为"a definition for..."
,但这里是{{ 1}})
答案 0 :(得分:6)
当您使用dynamic
时,您指示编译器使用反射来调用方法和访问属性。在您的情况下,您以这种方式访问的对象是匿名类型,匿名类型是internal
到它们创建的程序集。
为Razor视图生成的代码位于单独的程序集中,并且尝试反映在控制器中创建的匿名类型将失败。调试器不受此限制的影响,因此当反射失败并抛出异常时,您仍然可以检查调试器中匿名类型的属性。
这也解释了为什么在Razor视图中创建匿名类型时代码有效。然后,使用dynamic
生成的代码能够反映出不同类型,因为它是在同一个程序集中声明的。
基本上,在MVC Razor中,当它们在控制器中声明时,您无法在视图中使用匿名类型。您对dynamic
的使用通过生成难以理解的运行时错误来隐藏此基本问题。
要解决您的问题,您可以创建特定的公共类型,而不是使用内部匿名类型,或者您可以在控制器中convert the anonymous type to an ExpandoObject
。
答案 1 :(得分:1)
我认为View()
构造函数只是不知道要使用什么重载,因为你有dynamic
类型。您可以尝试这样做:
List<dynamic> foos = dbContext.Foos.Select(Foo.Projection()).ToList();
ViewData.Model = foos;
return View();
但是,如果您不使用任何强类型View
优势 ,为什么要使用强类型ViewModel
,比如类型检查和IntelliSense
?
如果您确实要将动态类型传递到{strong> MVC 3 之后的View
,则可以使用ViewBag
dynamic
。
在Controller
:
List<dynamic> foos = dbContext.Foos.Select(Foo.Projection()).ToList();
ViewBag = foos;
return View();
在View
:
@foreach (var x in ViewBag)
{
<span>@x.fooId</span><br />
}
答案 2 :(得分:0)
控制器内部 列表foos = dbContext.Foos.Select(Foo.Projection())。ToList();
return View(foos);
在侧剃刀视图中
@model List<dynamic>