2011-10-30 49 views
34

我很好奇人们构建ViewModel的各种方式,以及他们为什么选择这种方法。你如何填充/验证你的ViewModels?

我可以在这里想到几种方法:

-1。注入库 - 控制器将模型和映射加载到ViewModel。在这里,ViewModel的构造函数可以采用各种集合来为ex设置。在选择列表中,例如:

 

public CustomerController(ISomeRepository repository) 
{ 
    _repository = repository; 
} 

public ActionResult Create() 
{ 
    CustomerCreateViewModel model = new CustomerCreateViewModel(_repository.GetShipTypes, 
                   _repository.GetStates); 
.. 
.. 
} 
 

-2。 ViewModelBuilder - 在控制器中注入或实例化一个注入库的实例。通过一些所谓的像

>var orderViewModel = orderViewModelBuilder.WithStates().Build(orderId);

,或者

var orderViewModel = orderViewModelBuilder.WithStates().Build(orderId);

-3。直接在控制器(无需代码 - 其凌乱)

-4。返回域模型,控制器则映射或视图模型的一些其他服务(注射或没有)(任何人都这样做,以返回未明确指定的视图模型/注意到作为一个视图模型生成器类?)


public JobCreateViewModel BuildJobCreateViewModel(int parentId) 
{ 
    JobCreateViewModel model = new JobCreateViewModel(); 
    model.JobStatus = _unitOfWork.JobRepository.GetJobStatuses(); 
    model.States=_unitOfWork.StateRepository.GetAll(); 
    return model; 
} 

现在在回程中 - 关于验证视图模型 - 您是从基础ViewModel类继承以进行标准验证,还是在所有ViewModel之间复制验证(例如数据注释属性),还是仅仅依靠服务器端验证它可以全部通过你的域对象来验证吗?

其他?有什么更好的?为什么?

编辑 根据下面的链接,我在Jimmy Bogard的ViewModels体系结构中找到了一篇不错的文章。虽然它没有直接解决上述问题,但它对于任何来这里获取ViewModel信息的人来说都是一个很好的参考。 http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/

+0

这里有一个downvote - 只是好奇为什么 - 我可以澄清的任何东西? –

+4

在我的手机上,我试图星星时无意中点击了它 - 对不起。现在撤消已经太迟了。 – Jason

+0

ah不用担心的话:) –

回答

14

我向控制器注入服务,而不是存储库,然后使用AutoMapper将其转换为视图模型。在这种情况下,服务层的好处是它可以将一个或多个存储库中的多个简单操作合并为一个暴露域模型的操作。例如:

private readonly ICustomerService _service; 
public CustomerController(ICustomerService service) 
{ 
    _service = service; 
} 

[AutoMap(typeof(Customer), typeof(CustomerViewModel))] 
public ActionResult Create(int id) 
{ 
    Customer customer = _service.GetCustomer(id); 
    return View(customer); 
} 

在这个例子中是自动映射的自定义动作过滤器,我可以写其中控制器动作之后执行,检查返回的对象,并使用所定义AutoMapper映射到其映射到指定的目的地类型。所以视图将相应的CustomerViewModel作为模型类型。本来也等同于:

public ActionResult Create(int id) 
{ 
    Customer customer = _service.GetCustomer(id); 
    CustomerViewModel vm = Mapper.Map<Customer, CustomerViewModel>(customer); 
    return View(vm); 
} 

这只是实在是太多了管道和可以集中重复的代码。

我还建议你看Jimmy Bogard的putting your controllers on a diet video

+0

谢谢Darin。我看到有人演示了类似的AutoMap属性 - 我看到Jimmy有一个属性。你为这些视图模型的客户端验证做了什么(或者不是吗?)并在它们之间共享验证逻辑?你是否将你的仓库注入你的服务层? –

+0

@AdamTuliper,我使用FluentValidation.NET进行服务器端验证,并使用简单的客户端验证场景(要求,日期大于,...)。对于更复杂的客户端验证场景(依赖属性,...),我决定是否需要在客户端处理它,并且如果需要为这些场景执行客户端验证,我编写自定义jquery验证appender。就存储库到服务层而言,是的,服务层使用ctor注入来让所有的存储库允许在域模型上执行简单的CRUD操作。 –

+0

感谢达林,另一个很好的答案:) –

0

我们的方法是将存储库注入控制器并使用Automapper http://automapper.org/将其映射到ViewModel。我们的ViewModels包含数据注释属性,以允许客户端进行验证。

我们在存储库中调用返回域对象(实体框架)的方法。域对象被映射到ViewModel。我们倾向于使用相同的ViewModel进行编辑并添加,因此需要一次数据注释。在最简单的形式,它看起来像下面的代码:

public ActionResult List(int custId, int projId) 
    { 
     var users = _userRepository.GetByCustomerId(custId); 
     var userList = Mapper.Map<IEnumerable<CMUser>, IEnumerable<UserListViewModel>>(users); 
     return View(userList); 
    } 
+0

但是版本库没有映射到视图模型。必须在存储库中调用某个方法,以返回域对象或视图模型。此外,如果对每个模型或共享位置使用不同的注释,则这不包括。 –

+0

另外,如果使用相同的ViewModel进行编辑/添加,那么您将如何处理默认情况下需要使用数据注释的整数ID字段?如果从表单中遗漏,它将失败validaton。 Ints默认是必需的,所以你必须初始化为“创建”场景的0,否? –

1

我完成了一个项目,我们做了#4的变化。我们有一个注入控制器的服务类。服务类拥有存储库和模型构建器类(我们称之为模型工厂)的依赖关系。

控制器调用服务类,该类处理业务验证逻辑,然后从相应的工厂中提取视图模型。模型本身依靠数据注释进行输入验证。

它对我们的团队非常有用。有足够的关注点分离,允许开发者在不相互影响的情况下开展工作,但足以应付可理解的事情。

这是我们第一次尝试它,我们会坚持下去。我很想看看别人如何回应。

+0

谢谢。所以你的服务类反过来被注入存储库?什么是你的方法设置为像前例。在服务类?您是如何处理跨多个但相似视图模型的客户端验证的? (例如编辑与创建) –

+0

这与Darin下面的例子非常相似,我们有一个疯狂的要求,我们不能使用开源软件,所以我们不能使用Automapper。下次我们将用automapper替换视图模型工厂。我们使用Display和Editor模板来为相同模型的不同视图提供服务,数据注释为我们提供了我们需要的所有验证。 – Jason

+0

模型构建器类从构造函数参数(服务处理存储库对象)或模型构建器直接使用存储库本身接收存储库对象?你能提供一些非常简单的例子吗? – Muflix

0

我使用了一个服务层,它隐藏了控制器从服务方法返回ViewModel的域模型。这使我可以在不影响客户端的情况下更改域模型。