C# 服务层如何适合我的存储库实现?

C# 服务层如何适合我的存储库实现?,c#,asp.net,domain-driven-design,repository,repository-pattern,C#,Asp.net,Domain Driven Design,Repository,Repository Pattern,我创建了一个POCO模型类和一个处理持久性的存储库类。由于POCO无法访问存储库,因此存储库中有许多似乎不正确的业务逻辑任务。从我所读到的内容来看,似乎我需要一个位于UI使用者和存储库层之间的服务层。我不确定的是它到底应该如何工作 除了服务层之外,还应该有一个单独的业务逻辑层,还是服务层的角色 每个存储库应该有一个服务吗 服务层是UI实例化模型对象的唯一方式,还是存储库向服务提供新的模型实例 我是否将我的参数、模型和其他验证放在服务层中进行检查,以确保输入有效,并且在更新之前数据库中存在要更新的

我创建了一个POCO模型类和一个处理持久性的存储库类。由于POCO无法访问存储库,因此存储库中有许多似乎不正确的业务逻辑任务。从我所读到的内容来看,似乎我需要一个位于UI使用者和存储库层之间的服务层。我不确定的是它到底应该如何工作

除了服务层之外,还应该有一个单独的业务逻辑层,还是服务层的角色

每个存储库应该有一个服务吗

服务层是UI实例化模型对象的唯一方式,还是存储库向服务提供新的模型实例

我是否将我的参数、模型和其他验证放在服务层中进行检查,以确保输入有效,并且在更新之前数据库中存在要更新的项

模型、存储库和UI是否都可以调用服务层,还是只供UI使用

服务层应该是所有静态方法吗

从UI调用服务层的典型方式是什么

在模型和服务层上应该进行哪些验证

以下是我现有图层的一些示例代码:

public class GiftCertificateModel
{
    public int GiftCerticiateId {get;set;}
    public string Code {get;set;}
    public decimal Amount {get;set;}
    public DateTime ExpirationDate {get;set;}

    public bool IsValidCode(){}
}


public class GiftCertificateRepository
{
    //only way to access database
    public GiftCertificateModel GetById(int GiftCertificateId) { }
    public List<GiftCertificateModel> GetMany() { }
    public void Save(GiftCertificateModel gc) { }
    public string GetNewUniqueCode() { //code has to be checked in db }

    public GiftCertificateModel CreateNew()
    {
        GiftCertificateModel gc = new GiftCertificateModel();
        gc.Code = GetNewUniqueCode();
        return gc;
    }              
}

GCs的创建方式以及验证在实体/服务之间的分离方式似乎有问题。用户/消费者不必关心在哪个地方进行了哪些验证。。。建议?

您可以创建一个名为GiftCertificateService的服务

这样,您就可以将任何不属于GiftCertificateModel责任的任务协调到它的服务中。(不要与WCF服务混淆)

该服务将控制所有任务,因此您的UI(或任何可能的调用方)将使用服务中定义的方法

然后,服务将调用模型上的方法、使用存储库、创建事务等

例如(基于您提供的示例代码):

UI将调用CreateCertificate方法(传递参数等),该方法也可能返回一些内容

注意:如果你想让类在UI上运行,那么就创建一个控制器类(如果你在做MVC)或一个演示者类(如果你在做MVVM,并且不想把所有东西都放在ViewModel中),然后使用该类的GiftCertificateService。

看一看。它类似于构建ASP.NET MVC应用程序的最佳实践体系结构框架。一般架构模式是每个实体有一个存储库,仅负责数据访问,每个存储库有一个服务,仅负责业务逻辑和控制器与服务之间的通信

根据S#arp架构回答您的问题:

除了服务层之外,是否还应该有一个单独的业务逻辑层,或者这是服务层的角色?

模型应负责字段级验证(例如,使用所需的字段属性),而控制器可在保存前验证数据(例如,保存前检查状态)

每个存储库是否应该有一个服务层?

是的-每个存储库应该有一个服务(不是每个存储库都有一个服务层,但我猜你的意思是这样的)

服务层是UI可以实例化模型对象的唯一方式还是存储库向服务提供新的模型实例?

存储库和服务可以根据需要返回单个实体、实体集合或数据传输对象(DTO)。控制器将这些值传递给模型中的静态构造函数方法,该方法将返回模型的实例

使用DTO的ex:

GiftCertificateModel.CreateGiftCertificate(int GiftCerticiateId, string Code, decimal Amount, DateTime ExpirationDate)
我是否将参数、模型和其他验证放在服务层中进行检查,以确保输入有效,并在更新前确保数据库中存在要更新的项?

模型验证字段级值,例如通过检查所需字段、年龄或日期范围等确保输入有效。服务应执行任何需要在模型值之外进行检查的验证,例如检查礼品券是否尚未兑换,正在检查礼品券所针对的商店的属性)

模型、存储库和UI是否都可以调用服务层,还是只供UI使用?

控制器和其他服务应该是唯一调用服务层的服务。服务应该是唯一一个调用存储库的服务

服务层应该是所有静态方法吗?

它们可以是,但如果不是,则更容易维护和扩展。如果每个实体/子类有一个服务,那么对实体的更改和添加/删除子类更容易更改

从UI调用服务层的典型方式是什么?

调用服务层的控制器的一些示例:

giftCertificateService.GetEntity(giftCertificateId); (which in turn is just a call to the giftCertificateRepository.GetEntity(giftCertificateId)

giftCertificateService.Redeem(giftCertificate);
在模型和服务层上应该进行哪些验证?

上面已经回答了

更新

因为您使用的是WebForms,所以理解其中的一些概念可能有点困难,但我所提到的一切都是适用的,因为我所描述的是一个通用的MVC范例。用于数据访问的ADO.NET并不重要,因为数据访问是通过存储库解耦的

我是否向服务中添加与我的模型相同(可能更多)的属性(金额、代码等),还是只提供接受GiftCertificate对象和直接参数的方法?

您需要按照服务名称的确切含义来看待这些服务——控制器可以调用的操作。您不需要属性
GiftCertificateService gcService = new GiftCertificateService();
GiftCertificate gc = new GiftCertificate();

if (!gc.IsValidExpDate(inputExpDate))
{
    //give error to user..
}

//if no errors...
gc.Code = gcService.GetNewCode();
gc.Amount = 10M;
gc.ExpirationDate = inputExpDate;
gcService.SaveNewGC(gc);
//method updates the gc with the new id...
public class GiftCertificateService 
{
   public void CreateCertificate() 
   {
      //Do whatever needs to create a certificate.
      GiftCertificateRepository gcRepo = new GiftCertificateRepository();
      GiftCertificateModel gc = gcRepo.CreateNew();
      gc.Amount = 10.00M;
      gc.ExpirationDate = DateTime.Today.AddMonths(12);
      gc.Notes = "Test GC";
      gcRepo.Save(gc);
   }
}
GiftCertificateModel.CreateGiftCertificate(int GiftCerticiateId, string Code, decimal Amount, DateTime ExpirationDate)
giftCertificateService.GetEntity(giftCertificateId); (which in turn is just a call to the giftCertificateRepository.GetEntity(giftCertificateId)

giftCertificateService.Redeem(giftCertificate);
public class GiftCertificateModel
{
}
public class GiftCertificateRepository
{
   //Remove Model related code from here, and just put ONLY database specific code here, (no business logic also). Common methods would be Get, GetById, Insert, Update etc. 

    Since essence of Repository is to have common CRUD logic at one place soyou don't have to write entity specific code. 
    You will create entity specific repository in rare cases, also by deriving base repository.

}

public class GiftCertificateService()
{
    //Create Model instance here
    // Use repository to fill the model (Mapper)

}