在 Web 应用程序中分离 BLL、PL 和 DAL

Posted

技术标签:

【中文标题】在 Web 应用程序中分离 BLL、PL 和 DAL【英文标题】:Separating BLL, PL and DAL in a web application 【发布时间】:2011-12-10 18:19:51 【问题描述】:

我被要求开发一个可以有多个表示层的网络应用程序,目前它在网络上,但很快就会在桌面和其他平台上。所以我四处寻找如何做到最好。我发现使用分层方法更好。

我正在考虑将 BLL 作为一种 Web 服务,可以由不同的 PL 访问。 BLL 将访问 DAL 以进行数据特定操作。 到目前为止一切顺利,但我正在考虑将 ASP.NET MVC 用于 Web 应用程序。现在我有点困惑,因为“控制器”本质上包含业务逻辑,对吧。 这是一个不错的选择吗?如果我确实遵循相同的路径,使用 MVC 和上述层,我的控制器不一定包含 BLL,但只会是,有点傻瓜。

这是正确的做法吗?

【问题讨论】:

【参考方案1】:

这些是推荐的层:

演示文稿(MVC、WPF 等): 仅包含表示逻辑(从不包含业务逻辑)控制器仅处理与应用程序/服务层的通信以协调通信。

分布式服务(远程门面): 由于您将有许多客户端,其中一些是 Windows 应用程序,而另一些是 Web 应用程序,建议创建一个远程服务层(WCF 服务或 Web 服务),将业务层暴露给消费者(最好发送和接收 DTO)。

应用层: 处理与域层的通信,协调事务逻辑和技术服务的层,如果您使用 DTO,它将域对象转换为 DTO,反之亦然

域层: 包含实体和值对象,这是根据封装数据和逻辑的面向对象领域对象设计的业务逻辑的核心。如果使用存储库模式,它还可以包含存储库接口。以及不适合单个实体的逻辑的域服务。

数据访问: 使用 NHibernate 或 EF 等 ORM 或任何数据访问技术将实体映射到数据库表中。

基础设施/通用: 基础架构代码和跨领域技术服务,如日志记录

我将尝试给出一个关于每一层的小例子: 一个假设的不完整示例说您要激活采购订单

表示层(MVC):

public class PurchaseOrderController

  public ActionResult ActivateOrder(int id)
  
    var response = _orderManagementService.ActivateOrder(id); // Call distributed service (Web Service)

    if(response.Succeed)
      return new SuccessActionResult();
    else
      return new FailedActionResult(response.Reason);
  

分布式服务层(Web Service):

public class OrderManagementWebService : IOrderManagementService

  private readonly IOrderExecutionService _orderService;

  public OrderManagementWebService(IOrderExecutionService orderService)
  
    _orderService = orderService; // Order Service from application service
  

  public ActivationResult ActivateOrder(int id)
  
    var response = _orderService.ActivateOrder(id); // Call the application layer to execute the logic
    if(
  

应用层:

public class OrderExecutionService : IOrderExecutionService

  private IOrderRepository _orderRepository;

  public OrderExecutionService(IOrderRepository orderRepository)
  
    _orderRepository = orderRepository;
  

  public ActivationResult ActivateOrder(int id)
  
    var order = _orderRepository.GetById(id); // Get the order from repository

    try
    
      order.Activate(); // Call business logic inside the order entity
      return new ActivationResult  Success = true  ;
    
    catch(ActivationException ex)
    
      LogFactory.GetLog().Exception(ex); // Call log from infrastructure layer
      return new ActivationResult  Success = false, Reason = ex.Message  ;
    
  

领域层:

public class PurchaseOrder : Entity

  // Properties and fields (Data)
  public int Id  get; private set; 
  public Customer Customer  get; private set; 

  // Methods (contains business logic)
  public void Activate()
  
     if(Customer.IsBlacklisted)
       throw new InvalidCustomerException(...);

     if(_lineItems.Count == 0)
       throw new NoItemsException(...);

     this.SetStatus(OrderStatus.Active);

     .....
  

存储库(数据访问层):

public class OrderRepository : IOrderRepository

  public PurchaseOrder GetById(int id)
  
    // data access code to access ORM or any data access framework.
  

基础设施:

public class Logger : ILogger

  public void Exception(Exception ex)
  
   // write exception to whatever
  

【讨论】:

感谢@mohamed 的详细解释。我对您使用的一些关键字不是很清楚,我将尝试解释我所理解的。分布式服务最有可能出现在业务逻辑所在的位置。表示层也很清楚。但我不太确定应用层和域层。数据访问看起来只能由分布式服务访问,不会暴露在外部。还请解释基础设施/公共层。我知道我问了很多,在此先感谢。 为什么我们需要分布式服务层和应用层分开,分布式服务层没有太多有意义的代码? 正如我之前所说,只有当您打算拥有外部消费者(而不是您的内部 Web 应用程序)时 为什么我不能直接在 Web 服务上托管应用层?并让外部客户也使用它们? 因为应用程序层添加了一个级别或抽象,它协调事务逻辑和调用存储库,所有这些依赖项在 Web 服务上下文中都不需要,如果您正在开发内部 Web应用程序,您不需要调用 Web 服务,而是直接调用应用程序层,而无需访问 Web 服务抛出额外的 http 层

以上是关于在 Web 应用程序中分离 BLL、PL 和 DAL的主要内容,如果未能解决你的问题,请参考以下文章

在 node.js 中分离游戏服务器和 Web 服务器

ASP.NET 5 ,想要将实体框架从 Web 项目中分离出来

通用 DAL / BLL 类

如何在另一个项目中分离实体框架

在绘图应用程序中分离模型和视图/控制器

在 Flask 中分离 html 和 JavaScript [重复]