Asp.net mvc ASP.NET MVC仍然在存储库和解耦方面迷失方向

Asp.net mvc ASP.NET MVC仍然在存储库和解耦方面迷失方向,asp.net-mvc,repository-pattern,coding-style,Asp.net Mvc,Repository Pattern,Coding Style,我仍然在不断地寻求建立(并理解)现代编程惯例,如解耦、IoC、DI等。我正在努力找出如何建立一个存储库。我已经检查了这篇文章,它对我很有帮助,但是我仍然有一些问题一直困扰着我 我现在有我的程序在4层 Web(Project | ASP.NET MVC应用程序)-参考Models.dll和Persistence.dll 模型(域对象) 持久性(域对象的Fluent nHibernate映射) 实用程序(提供程序、存储库) 现在,我正在尝试编写一个简单的成员存储库。我的第一个任务 检查某人尝试注册时

我仍然在不断地寻求建立(并理解)现代编程惯例,如解耦、IoC、DI等。我正在努力找出如何建立一个存储库。我已经检查了这篇文章,它对我很有帮助,但是我仍然有一些问题一直困扰着我

我现在有我的程序在4层

Web(Project | ASP.NET MVC应用程序)-参考Models.dll和Persistence.dll

模型(域对象)

持久性(域对象的Fluent nHibernate映射)

实用程序(提供程序、存储库)

现在,我正在尝试编写一个简单的成员存储库。我的第一个任务

检查某人尝试注册时是否存在电子邮件地址。这一切似乎都很好,所以我去试着想办法把它放在哪里

不过,一开始,我只是将它放在
MembershipProvider
CreateUser
方法中。但是,这存在于Utilities项目中。到目前为止,公用事业公司还不了解nHibernate。只有持久性项目才了解nHibernate

因此,我的
CreateUser
方法需要查询我的数据库。那么这里的最佳实践是什么?我是否在
Persistence
项目中创建一个
UserRepository
,然后创建一个名为
CheckEmail
的完整方法?或者我只是将nHibernate.dll添加到我的
实用程序
项目中,并在提供程序中编写会话查找


在我的持久性项目中,创建执行特定操作的存储库似乎比创建提供者的工作要多。如果我必须为提供者创建存储库,为什么还要创建提供者?所有这些新方法的目的不是为了阻止代码重复吗?但感觉就像是要把事情“分开”一样,我必须写2到3次相同的代码。这里的最佳实践是什么?

您的存储库应该真正在持久性程序集中实现。假设您正在对它们进行单元测试,您将为域程序集中的每个存储库定义接口

您的
CreateUser
方法不应直接查询数据库以确定电子邮件地址是否已存在,而应在您的
DoesEmailExist
中创建一个单独的方法,负责执行该检查。每种方法都应该有一个单一的责任

回应jfar的质疑:

没错,域定义了可以做什么,定义了接口,如
domain.IUserRepository.Create(User)
。然而,域没有定义任何实现

假设您从使用实体框架开始,您可以创建一个
持久性
程序集,该程序集实现域中定义的接口。因此,下面我们从上面的域接口实现该接口:

namespace Persistence
{
    public class UserRepository : Domain.IUserRepository
    {
        public void Create(User user)
        {
           // use Entity Framework to persist a user
        } 
    }
}
例如,假设您的客户稍后告诉您实现一个NHibernate持久层。幸运的是,我们的域与现有的持久层是分开的——它位于域中。因此,您可以轻松地实现现有的域接口,而无需更改MVC应用程序中的任何代码,因为您所知道的只是您定义的接口,而不是实体框架实现

然后可以将IoC容器配置为解析
IUserRepository
,因为无论是实体框架还是NHibernate实现,MVC应用程序都不在乎

就程序集引用而言,
持久化
程序集引用了
,而
没有引用
持久化

这导致了一种易于测试和更改的解耦设计,从而更易于维护


我希望这会有所帮助。

存储库接口应该放在域层,这个存储库的实现将是基础结构层上的NHibernate类。您的UI层了解基础架构,但只依赖于将手动或通过DI容器注入的存储库接口。

我使用以下约定来帮助我决定是否使用上述功能:

案例:检查用户注册时是否已存在电子邮件地址

1-验证类型:输入验证
说明:是有效格式、长度、字符等的电子邮件。
完成者:设置属性时用户对象,否则将引发异常

2-验证类型:业务规则验证
说明:是否已经存在具有相同电子邮件的用户或任何此类业务规则?
完成者:用户存储库,因为它能够在调用提交之前查询所有用户以查找此信息

基于此,我的用户代码如下所示:

// Method - can be called by the Controller layer to register a user  
// Can be a private method of the controller itself or can be abstracted by a   
// IAccountManager implementation with this method  
void RegisterUser(string emailId){

var user = new User();
user.Email = emailId;

if(!user.IsValid){
 // Some input data is not correct
 // Handle the case & exit this method
}

var repository = serviceLocator.GetInstance<IUserRepository>();
repository.Save(user);
if(!repository.IsValid){
 // Some business rule error 
 // Handle the case & exit this method
}
else{
 repository.Commit();
}
}
//方法-可由控制器层调用以注册用户
//可以是控制器本身的私有方法,也可以由
//IAccountManager使用此方法实现
无效注册表服务器(字符串emailId){
var user=新用户();
user.Email=emailId;
如果(!user.IsValid){
//某些输入数据不正确
//处理案例并退出此方法
}
var repository=serviceLocator.GetInstance();
保存(用户);
如果(!repository.IsValid){
//某些业务规则错误
//处理案例并退出此方法
}
否则{
repository.Commit();
}
}
因此,虽然我知道您在查看所有图层时遇到困难,但我将其归类为:

Web项目-是应用程序的视图部分&只有数据逻辑才能输出视图
模型-具有验证自身逻辑的POCO