【问题标题】:Problem with model encapsulation in business logic layer业务逻辑层的模型封装问题
【发布时间】:2019-05-22 22:06:25
【问题描述】:

我有一个带有控制器、服务和存储库的典型应用程序。所以,有2个项目:

  • 带有控制器的 ASP.NET Core WebAPI
  • 包含所有业务逻辑的核心

WebAPI 应该只知道来自 Core 的服务。在核心中,我有返回 DTO 的公共类(服务),但这些服务取决于我想标记为 internal 的 DbContext。当然不能

错误 CS0051 可访问性不一致:参数类型 'DevicesDbContext' 比方法更难访问 'DeviceService.DeviceService(DevicesDbContext, IMapper)'

我正在使用 EF Core 和 instead of own Repositories I use DbContext。我有只能在核心项目中使用的实体模型。您能否建议我如何实现这一目标?

例如我的模型是:

internal class Device
{ 
   public int Id {get;set;}
}

数据库上下文:

internal class DevicesDbContext : DbContext
{
   public DbSet<Device> Devices {get;set;}
}

服务:

public class DeviceService : IDeviceService
{
   public DeviceService(DevicesDbContext dbContext, IMapper mapper)
   { 
   }
   ..
}

我在 DeviceService 的构造函数中遇到了这个错误。这不是duplicate,因为我知道该错误的含义以及如何解决该错误。在这里我询问了这种方法的设计或架构,因为我需要避免在 WebAPI 中直接使用模型和 dbcontext

【问题讨论】:

  • 请问您为什么要将 DevicesDbContext 设为内部?在我看来,Device 和 DeviceDbContext 都应该是公开的。其次,您可以将您的 DTO 模型放在一个新的核心项目中。这可能会让你的责任更加明显。也许尝试将 DbContext 设置为受保护而不是内部?
  • @ZakkDiaz 我想将其设为内部以避免直接在 WebAPI 中使用它
  • “设计或架构”对于 SO 来说有点宽泛。您可能(例如,您应该先阅读他们的帮助中心)可以在Software Engineering 上提出这个问题,但我认为,就像这里一样,他们更喜欢更具体地了解您的身份寻找。
  • @Greg 我在核心项目的 DI 中注册了它。我没有说我想在不注册的情况下注入上下文

标签: c# entity-framework oop asp.net-core


【解决方案1】:

如果您不想使用存储库来保护数据访问(通常仍返回实体,而不是 DTO,因此实体需要公开),那么真正的问题是: “为什么要避免在 Web API 中使用 DbContext 和实体?”

Entity Framework 是一个框架。它的目的是促进数据访问,使您的代码更容易编写和更容易理解。就像您选择使用 .Net 框架并通过选择 EF 来利用 Linq、Generic 等东西一样,您应该寻求利用它提供的一切。

如果您绝对必须将上下文和实体排除在 API 程序集引用之外,或者希望在 Web API 和另一组 MVC 控制器之间集中涉及实体的业务逻辑,那么您正在考虑构建一个贫乏的 API。在这种情况下:

Services.DLL -- 引用 DbContext、实体..

public interface ISomethingService
{
  IEnumerable<SomeDto> GetSome(/*params*/);
}

public class SomethingService : ISomethingService
{
    public SomethingService(SomeDbContext context) 
    { // Init stuff. 
    }

    IEnumerable<SomeDto> ISomethingService.GetSome()
    {
       // Get some stuff and return DTOs.
    }
}

Web API DLL -- 仅引用 DTO。

public class SomeAPI : ISomethingService
{
    private ISomethingService Service { get; set; }
    public SomeAPI(ISomethingService service)
    {
        Service = service;
    }

    public IEnumerable<SomeDto> GetSome()
    {
        return Service.GetSome();
    }
}

API 很弱,因为它只是将请求传递给公共服务并转发响应。 API 不需要实现相同的接口,它可以简单地接受对服务的引用并使用它,通过任何参数来获取它将传回的 DTO。

这种方法的缺点是要修改您在 API 和服务层之间切换的服务,而不是仅在 API 中工作。我不赞成使用这样的方法,因为 API 等通常需要考虑过滤、分页等细节,因此我想利用 EF 提供的出色 LINQ 功能。我还大量利用 EF 的 IQueryable 支持来保持我的数据访问层简单和紧凑,让消费服务决定如何获取他们需要的细节。用额外的服务边界掩盖这一点会增加复杂性和低效率,因为它会导致复杂的代码、许多非常相似的函数和/或浪费内存/处理以返回不需要的数据。

【讨论】:

    猜你喜欢
    • 2011-10-17
    • 2011-07-27
    • 2015-11-07
    • 2012-04-25
    • 2010-12-18
    • 2012-03-14
    • 2011-12-03
    • 2011-11-26
    • 2017-04-29
    相关资源
    最近更新 更多