通常在我创建MVC视图时,我首先将视图绑定到ExpandoObject
,这样我就可以快速找出视图模型的形状,而无需花时间添加/修改/删除实际属性。强类型视图模型。
但是一旦我对我的视图模型看起来有一个很好的感觉,我更喜欢为它创建一个实际的类。如果我可以从ExpandoObject自动生成视图模型,那就太棒了。这可能吗?
public virtual ActionResult DoStuff(int stuffId)
{
// eventually this stuff gets moved to a service class
dynamic vm = new ExpandoObject();
using (var ctx = new MyContext())
{
vm.Stuff = ctx.Stuff
.Where(x => x.Id == stuffId)
.Select(x => new
{
Foo = x.Foo,
Bar = x.Bar
}).SingleOrDefault().ToExpando();
}
// once I know what vm looks like, I'll want to do this to easily create a new class
// string stronglyType = GenerateStronglyTypeClass(vm);
return View(vm);
}
public string GenerateStronglyTypedClass(ExpandoObject object)
{
// what goes here??
}
答案 0 :(得分:2)
我首先将我的视图绑定到ExpandoObject,这样我就能很快发现 我的viewmodel的形状,而不必花时间 在强类型中添加/修改/删除实际属性 视图模型。
嗯,你在做什么是非常糟糕的。很抱歉这样说但是你输了很多。我无法相信人们实际上发现在项目的Models
文件夹中使用 Ctrl + A 这么难,键入一些以ViewModel
结尾的名称,然后键入a几个 prop + Tab + Tab 并定义一个真正的强类型视图模型。
相反,人们尝试使用一些expandos,动态,ViewDatas,ViewBags,CrapBags,......
所以我建议你这样做:使用真实视图模型并忘记那些周输入,否则你将继续挣扎于ASP.NET MVC。相信我。它是这样的: - )
当您使用AutoMapper自动绑定域模型和视图模型时,您将有更多时间喝啤酒,就像我一样:
public ActionResult DoStuff(int stuffId)
{
using (var ctx = new MyContext())
{
var model = ctx.Stuff.Where(x => x.Id == stuffId);
var vm = Mapper.Map<IEnumerable<MyDomainModel>, IEnumerable<MyViewModel>>(model);
return View(vm);
}
}
看看这有多有趣?
显然,如果您希望有机会对控制器操作进行单元测试,那么您应该使用存储库而不是硬编码控制器中的Linq-To-I-DO-Know-What-What-context,如下所示:
public ActionResult DoStuff(int stuffId)
{
var model = _stuffRepository.GetStuffs(stuffId);
var vm = Mapper.Map<IEnumerable<MyDomainModel>, IEnumerable<MyViewModel>>(model);
return View(vm);
}
这么难吗?
你甚至可以写一个custom action automapper属性,你的行动甚至可能是这样的:
[AutoMap(typeof(IEnumerable<MyDomainModel>), typeof(IEnumerable<MyViewModel>))]
public ActionResult DoStuff(int stuffId)
{
var model = _stuffRepository.GetStuffs(stuffId);
return View(model);
}
好的,我们越来越短,越来越轻。控制器动作究竟应该如何。 On a diet
答案 1 :(得分:1)
运行时生成的任何类型的类(带有发出)都不会带来很多好处,因为如果你不知道编译类型的类型,你仍然会调用动态,而expando实际上会击败poco在我的测试中上课。如果你的generate类要创建一个可以工作的c#文件,但你必须包含该文件并替换代码,重新编译,呃,但是可以工作。
开源框架ImpromptuInterface有一个builder syntax,它允许您以相同的方式分配属性或创建对象图形,无论类型是什么(expando或poco),只需更改几个类型。
dynamic New = Builder.New<ExpandoObject>();
var person = New.Person(
FirstName: "George",
LastName: "Washington"
);
然后在开发过程中,您可以定义静态类型
public class Person{
public string FirstName{get;set;}
public string LastName{get;set;}
}
dynamic New = Builder.New<Person>();
Person person = New.Person( //we are static typing after this point
FirstName: "George",
LastName: "Washington"
);
它还有一些其他功能,比如在运行时包装静态接口,这对您来说也很有用。