ASP.NET MVC 架构:ViewModel 是通过组合、继承还是复制? [英] ASP.NET MVC Architecture : ViewModel by composition, inheritance or duplication?

查看:19
本文介绍了ASP.NET MVC 架构:ViewModel 是通过组合、继承还是复制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是 ASP.NET MVC 3 和 Entity Framework 4.1 Code First.

I'm using ASP.NET MVC 3 and Entity Framework 4.1 Code First.

假设我有一个 User 实体:

Let's say I have a User entity :

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }        
}

在我的 UserController 中编辑它时,我想添加一个 PasswordConfirmation 字段并验证 PasswordConfirmation == Password

When editing it in my UserController I want to add a PasswordConfirmation field and verify that PasswordConfirmation == Password

我的第一次尝试是:

public class EditUserModel
{
    [Required]
    public User User { get; set; }

    [Compare("User.Password", ErrorMessage = "Passwords don't match.")]
    public string PasswordConfirmation { get; set; }
}

在这种情况下,客户端验证有效但(客户端验证工作是巧合.)不起作用服务器端验证失败并显示以下消息:找不到名为 User.Password 的属性

In this case the client side validation works but ( client side validation working was a coincidence.) doesn't work and the server side validation fails with the following message : Could not find a property named User.Password

在这种情况下,我认为最好的解决方案是创建一个自定义的 CompareAttribute

I think the best solution, in this case, would be to create a custom CompareAttribute

实现IValidatableObject

public class EditUserModel : IValidatableObject
{
    [Required]
    public User User { get; set; }
    public string PasswordConfirmation { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if(this.PasswordConfirmation != this.User.Password)
            return new[] { new ValidationResult("Passwords don't match", new[] { "PasswordConfirmation " }) };

        return new ValidationResult[0];
    }
}

在这种情况下,服务器端验证有效,但客户端验证不再起作用.实现 IClientValidatable 似乎有点太复杂了,我更喜欢在这种情况下不进行客户端验证.

In this case the server side validation works but the client side validation doesn't work anymore. Implementing IClientValidatable seems a bit too complicated and I prefer not having client side validation in this case.

public class EditUserModel : User
{
    [Compare("Password", ErrorMessage = "Passwords don't match.")]
    public string PasswordConfirmation  { get; set; }
}

当尝试使用 EF 直接保存 EditUserModel 时,它不起作用,我收到一些关于 EditUserModel 元数据的错误消息,所以我正在使用 AutoMapperUser 转换为 EditUserModel 并反向转换.这个解决方案有效,但它更复杂,因为我必须从模型转换到视图模型并反向转换.

When trying to directly save EditUserModel using EF it doesn't work, I get some some error message about the EditUserModel metadata so I'm using AutoMapper to convert from User to EditUserModel and backwards. This solution works but it more complex because I have to convert from the model to the view model and backwards.

(由 Malte Clasen 推荐)

视图模型将拥有模型的所有属性以及额外的属性.AutoMapper 可用于从一种转换到另一种.

The view model would have all the properties of the model plus additional ones. AutoMapper can be used to convert from one to another.

public class EditUserModel {    
  public string Name { get; set; }    
  public string Email { get; set; }    
  public string Password { get; set; }   
  [Compare("Password", ErrorMessage = "Passwords don't match.")]     
  public string ConfirmPassword { get; set; }        
}

这是我最不喜欢的解决方案,因为代码重复 (DRY)

This is the solution I like the least because of code duplication (DRY)

问题

在这种情况下,继承、组合和复制的优缺点是什么?

What are the pros and cons of inheritance, composition and duplication in this case ?

是否有一种简单的方法可以同时进行客户端和服务器端验证,而无需将模型转换为视图模型并反向转换?

Is there a simple way to have both client side and server side validation without having to convert the model to the view model and backwards ?

推荐答案

我之前一直在为这个问题苦苦挣扎,但在各种情况下,我都解决了这三个问题.一般来说,我看到的大多数意见都赞成在 MVC 项目中进行重复,并为每个视图专门构建一个 ViewModel.通过这种方式,您将使用的约定类似于 UserDetailsViewModelUserCreateViewModel.正如您所说,届时将使用 AutoMapper 或其他一些自动映射工具将域对象转换为这些平面视图模型.

Having struggled with this question before, I have in various instances gone with all three. In general, most of the opinions I've seen favor duplication in an MVC project, with a ViewModel constructed specifically for each view. In this manner the convention you'd use is something like UserDetailsViewModel and UserCreateViewModel. As you said, at that point AutoMapper or some other auto mapping tool would be used to convert from your domain objects to these flat ViewModels.

虽然我也不喜欢重复代码,但我也不喜欢用验证或其他特定于视图的属性污染我的域对象.另一个优点,尽管不可否认,几乎没有人会不得不与之抗衡(不管所有专业人士怎么说),是您可以以某种方式操纵域对象,而不必操纵您的 ViewModel.我提到它是因为它经常被引用,而不是因为它对我来说很重要.

While I, too, don't like repeating code, I also don't like polluting my domain objects with validation or other view-specific attributes. Another advantage, though admittedly one almost nobody would ever have to contend with (regardless of what all the pros say), is that you can manipulate your domain objects in some ways without necessarily manipulating your ViewModels. I mention that because it's commonly cited, not because it carries much weight for me.

最后,使用真正扁平的 ViewModel 可以使标记更清晰.当我使用组合时,我经常在创建名称类似于 User.Address.Street 的 HTML 元素时出错.平面 ViewModel 至少减少了我这样做的可能性(我知道,我总是可以使用 HtmlHelper 例程来创建元素,但这并不总是可行的).

Lastly, using a truly flat ViewModel makes for cleaner markup. When I've used composition, I've often made errors creating HTML elements with names that are something like User.Address.Street. A flat ViewModel reduces at least my likelihood of doing that (I know, I could always use HtmlHelper routines to create elements, but that's not always feasible).

无论如何,我最近的项目现在也几乎需要单独的 ViewModel.它们都基于 NHibernate,并且在 NHibernate 对象上使用代理使得无法直接将它们用于视图.

My recent projects have also pretty much required separate ViewModels these days anyway. They've all been NHibernate-based, and the use of proxies on NHibernate objects makes it not possible to use them directly for views.

更新 - 这是我过去提到的一篇好文章:http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx

Update - here's a good article I've referred to in the past: http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx

这篇关于ASP.NET MVC 架构:ViewModel 是通过组合、继承还是复制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆