我使用ASP.NET MVC 3和实体框架4.1代码优先。
假设我有一个User
实体:
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
我的第一次尝试是:
public class EditUserModel
{
[Required]
public User User { get; set; }
[Compare("User.Password", ErrorMessage = "Passwords don't match.")]
public string PasswordConfirmation { get; set; }
}
在这种情况下,客户端验证 是(客户端验证工作是巧合。)不起作用,并且服务器端验证失败,并显示以下消息:无法找到名为User.Password的属性
我认为最好的解决方案,在这种情况下,将创建一个自定义 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
看起来有点太复杂,我更喜欢在这种情况下没有客户端验证。
public class EditUserModel : User
{
[Compare("Password", ErrorMessage = "Passwords don't match.")]
public string PasswordConfirmation { get; set; }
}
当试图直接保存EditUserModel
使用EF它不工作,我得到一些一些错误信息有关的EditUserModel
元数据,以便我使用AutoMapper要转换User
到EditUserModel
和倒退。此解决方案的工作原理,但它更复杂,因为我必须从模型转换到视图模型和向后。
(由Malte Clasen推荐)
视图模型将具有模型的所有属性和附加属性。AutoMapper可以用来从一个转换到另一个。
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)
问题
在这种情况下继承,组成和重复有什么优点和缺点?
有没有一种简单的方法来同时进行客户端和服务器端验证,而无需将模型转换为视图模型和向后?
发布于 2018-03-26 09:43:10
在之前一直与这个问题斗争的时候,我已经在三种情况下都走了。总的来说,我在MVC项目中看到的大多数意见都支持复制,并且专门为每个视图构建了ViewModel。以这种方式,你会使用的约定是UserDetailsViewModel
和UserCreateViewModel
。正如你所说的那样,那时AutoMapper或其他一些自动映射工具将被用来从你的域对象转换到这些平面ViewModels。
虽然我也不喜欢重复代码,但我也不喜欢使用验证或其他视图特定的属性来污染我的域对象。另一个好处,尽管几乎没有人会与之抗衡(无论专业人士说什么),但是可以通过某些方式操纵域对象,而无需操纵ViewModel。我提到这是因为它通常被引用,并不是因为它对我很重要。
最后,使用真正平坦的ViewModel可以实现更清晰的标记。当我使用了构图时,我经常会用创建类似名称的HTML元素来创建错误User.Address.Street
。一个平面ViewModel至少减少了我做这件事的可能性(我知道,我总是可以使用HtmlHelper例程来创建元素,但这并不总是可行)。
无论如何,我最近的项目也需要单独的ViewModel。他们都是基于NHibernate的,并且在NHibernate对象上使用代理使得不可能直接将它们用于视图。
这是我以前提到的一篇很好的文章:http : //geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx
https://stackoverflow.com/questions/-100007775
复制相似问题