我正在尝试理解和设计您的应用/域模型(POCO / DTO)的良好实践。
假设我有以下数据库表,帐号:
UserID int
Email varchar(50)
PasswordHash varchar(250)
PasswordSalt varchar(250)
当然,EF4会像这样构建实体:
public class Account
{
public int UserID { get; set; }
public string Email { get; set; }
public string PasswordHash { get; set; }
public string PasswordSalt { get; set; }
}
现在,假设我有一个用于注册新用户的视图模型,可能看起来像这样:
public class RegistrationViewModel
{
public string Email { get; set; }
public string Password { get; set; }
}
最后,我有一项需要注册用户的服务:
public class RegistrationService
{
public void RegisterUser(??? registration)
{
// Do stuff to register user
}
}
我正在试图弄清楚要传递给RegisterUser方法的内容。当然,视图模型位于我的Web应用程序(表示层)下,因此我不希望将其传递给我的服务。
所以,我正在考虑四种可能性之一:
1)设置与RegistrationViewModel类似(如果不相同)的服务模型,并使用:
public class RegistrationServiceModel
{
public string Email { get; set; }
public string Password { get; set; }
}
public class RegistrationService
{
public void RegisterUser(RegistrationServiceModel registration)
{
// Do stuff to register user
}
}
2)设置模型的接口,并在我的视图模型中继承它,并设置我的方法接受接口:
public interface IRegistrationModel
{
string Email;
string Password;
}
public class RegistrationServiceModel : IRegistrationModel
{
public string Email { get; set; }
public string Password { get; set; }
}
public class RegistrationService
{
public void RegisterUser(IRegistrationModel registration)
{
// Do stuff to register user
}
}
3)传入Account实体,在我的控制器中执行RegistrationViewModel-to-Account映射:
public class RegistrationService
{
public void RegisterUser(Account account)
{
// Do stuff to register user
}
}
4)将我的视图模型从演示文稿移到域/服务层,并将其传递给服务方法:
public class RegistrationService
{
public void RegisterUser(RegistrationViewModel account)
{
// Do stuff to register user
}
}
这三种情况都不是理想的,因为我看到每种情况都存在问题。所以我想知道是否有另一种我无法想到的方法。
有什么好的做法?
提前致谢。
答案 0 :(得分:9)
确定使用第三次选项。正如šljaker所说,服务应该不知道应用程序的呈现部分(您的ViewModel是其中的一部分)。
当然,也不要通过包含大量过渡模型(如RegistrationServiceModel
)或 - 甚至更糟 - IRegistrationModel
(最后一个会导致“界面爆炸”一天)来使周围的事情过于复杂化。
所以:
ViewModel
。严格的ViewModel(与您的View一致1:1)的副作用优点是完全没有过度发布和欠发布问题。这取决于你的具体情况/品味。ViewModel
将传入的FormCollection
或IModelBinder
映射到您的实体。答案 1 :(得分:8)
您永远不会将视图模型传递给服务。服务甚至不知道您可能已在表示层中定义的视图模型的存在。服务适用于域模型。
使用Auto mapper在视图模型和域模型之间进行映射,反之亦然。
就个人而言,我从未听说过DDD中的服务模型(服务的视图模型)。
答案 2 :(得分:3)
在这种情况下,使用DTO(数据传输对象)非常有意义。您可以在服务层创建一个AccountDto
类,并使用它将注册数据传递给服务。在某些情况下,它可能类似于ViewModel,但通常您可以在View中显示比创建用户所需的更多内容。为了进一步说明这一点,您的ViewModel可能至少看起来像这样:
public class RegistrationViewModel
{
[Required]
public string Email { get; set; }
[Required]
public string Password { get; set; }
[Required]
[Compare("Password")]
public string RepeatPassword { get; set; }
}
虽然您的DTO只需要Email
和Password
属性。
public class AccountDto
{
public string Email { get; set; }
public string Password { get; set; }
}
如您所见,ViewModel
仅包含View
所需的数据。电子邮件验证和密码比较逻辑发生在Web层中。您使用DTO只获取服务的电子邮件和密码。然后在服务层您散列密码,填充您的Entity对象并将值保存到数据库。