当前位置:  开发笔记 > 后端 > 正文

ASP.NET MVC Web应用程序中的控制器是应该调用存储库,服务还是两者?

如何解决《ASP.NETMVCWeb应用程序中的控制器是应该调用存储库,服务还是两者?》经验,为你挑选了2个好方法。

我的ASP.NET MVC Web应用程序中的控制器开始变得有点臃肿与业务逻辑.Web上的示例都显示了简单的控制器操作,这些操作只是将数据从存储库中提取出来并将其传递给视图.但是如果你还需要支持业务逻辑呢?

比如说,履行订单的动作也需要发送电子邮件.我是否将其粘贴在控制器中并将此逻辑复制/粘贴到同时满足订单的任何其他操作?我的第一个直觉是创建一个像OrderFulfillerService这样的服务来处理所有这些逻辑并让控制器动作调用它.但是,对于从数据库中检索用户列表或订单等简单操作,我希望直接与存储库进行交互,而不是让服务包含该调用.

这是一种可接受的设计模式吗?控制器操作在需要数据访问时需要业务逻辑和存储库时调用服务?



1> Pure.Krome..:

您的控制器(在MVC项目中)应该在Service项目中调用您的对象.服务项目是处理所有业务逻辑的地方.

一个很好的例子是这样的:

public ActionResult Index()
{
    ProductServices productServices = new ProductServices();

    // top 10 products, for example.
    IList productList = productServices.GetProducts(10); 

    // Set this data into the custom viewdata.
    ViewData.Model = new ProductViewData
                         {
                             ProductList = productList;
                         };

    return View();
}  

或者使用依赖注入(我的收藏)

// Field with the reference to all product services (aka. business logic)
private readonly ProductServices _productServices;

// 'Greedy' constructor, which Dependency Injection auto finds and therefore
// will use.
public ProductController(ProductServices productServices)
{
    _productServices = productServices;
}

public ActionResult Index()
{
    // top 10 products, for example.
    // NOTE: The services instance was automagically created by the DI
    //       so i din't have to worry about it NOT being instansiated.
    IList productList = _productServices.GetProducts(10); 

    // Set this data into the custom viewdata.
    ViewData.Model = new ProductViewData
                         {
                             ProductList = productList;
                         };

    return View();
}

现在..什么是服务项目(或什么是ProductServices)?这是一个包含业务逻辑的类库.例如.

public class ProductServices : IProductServices
{
    private readonly ProductRepository _productRepository;
    public ProductServices(ProductRepository productRepository)
    {
        _productRepository = productRepository;
    }

    public IList GetProducts(int numberOfProducts)
    {
        // GetProducts() and OrderByMostRecent() are custom linq helpers...
        return _productRepository.GetProducts()
            .OrderByMostRecent()
            .Take(numberOfProducts)
            .ToList();
    }
}

但这可能是如此的核心和混乱...所以ServiceProduct类的简单版本可能是(但我不会真的推荐)...

public class ProductServices
{
    public IList GetProducts(int numberOfProducts)
    {
        using (DB db = new Linq2SqlDb() )
        {
            return (from p in db.Products
                    orderby p.DateCreated ascending
                    select p).Take(10).ToList();
        }
    }
}

你去吧 您可以看到所有逻辑都在Service项目中,这意味着您可以在其他地方重用该代码.

我在哪里学到这个?

来自Rob Conery的MVC StoreFront媒体和教程.切片面包以来最好的东西.他的教程用完整的解决方案代码示例详细解释了(我做了什么).他使用依赖注入这是SOO kewl,因为我已经看到他在MVC中如何使用它.

HTH.


@ Pure.Krome - 我认为这让我感到困惑,因为我在OOP中"长大"的基本解释是对象是数据*和*操作它们的方法.将项目拆分为"纯数据"实体和服务似乎违反了该方法.

2> 小智..:

我不确定为此使用服务.

据我所知,DDD的原则之一(我现在正在阅读)是域对象被组织成聚合,当你创建聚合根的实例时,它只能直接处理Aggregate中的对象(以帮助保持清晰的责任感).

创建聚合应该强制执行任何不变量等.

以Customer类为例,Customer可能是Aggregate root,而Aggregate中的另一个类可能是Address.

现在,如果要创建新Customer,则应该可以使用Customer构造函数或工厂来执行此操作.这样做应该返回一个在Aggregate边界内完全正常运行的对象(因此它不能处理Products,因为它们不是Aggregate的一部分,但它可以处理Addresses).

数据库是次要问题,只有将Aggregate持久保存到数据库或从数据库中检索它才能发挥作用.

为了避免直接与数据库连接,您可以创建一个Repository接口(如上所述),该接口给定Customer实例(包括对Address的引用)应该能够将Aggregate持久保存到数据库中.

关键是Repository接口是域模型/层的一部分(Repository的实现不是).另一个因素是存储库可能最终应该调用相同的"创建"方法,就像创建新对象(维护不变量等)一样.如果您正在使用构造函数,这很简单,因为当存储库仍然从数据"创建"对象时,您将最终调用构造函数.

应用程序层可以直接与域通信(包括存储库接口).

因此,如果您想创建一个对象的新实例,您可以例如

Customer customer = new Customer();

如果应用程序需要从存储库中检索客户的实例,那么没有特别的理由我可以想到它不会调用...

Customer customer = _custRepository.GetById(1)

要么...

Customer customer = _custRepository.GetByKey("AlanSmith1")

最终,它将以Customer对象的一个​​实例结束,该对象在其自身的限制和规则中运行,就像它直接创建新的Customer对象一样.

我认为服务应该保留在你试图使用的"东西"不是一个对象时.大多数规则(约束等)可以作为域对象本身的一部分编写.

一个很好的例子就是我正在阅读的DDD Quickly pdf.在那里,他们对Bookshelf对象有一个约束,你只能添加书架可以包含的书籍.

在将Book添加到BookShelf的Book对象集合之前,调用BookShelf对象上的AddBook方法会检查该空间是否可用.一个简单的示例,但业务规则由域对象本身强制执行.

顺便说一句,我不是说上面的任何一个都是正确的!我现在正试图解决所有这些问题!

推荐阅读
臭小子
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有