C# 业务逻辑层中的模型封装问题

C# 业务逻辑层中的模型封装问题,c#,entity-framework,oop,asp.net-core,C#,Entity Framework,Oop,Asp.net Core,我有一个带有控制器、服务和存储库的典型应用程序。因此,有两个项目: 带控制器的ASP.NET核心WebAPI 以所有业务逻辑为核心 WebAPI应该只知道来自Core的服务。在核心中,我有返回DTO的公共类(服务),但这些服务依赖于我想标记为内部的DbContext。我当然不能 错误CS0051可访问性不一致:参数类型 “DevicesDbContext”的可访问性不如方法 'DeviceService.DeviceService(DevicesDbContext,IMapper)' 我正在

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

  • 带控制器的ASP.NET核心WebAPI
  • 以所有业务逻辑为核心
WebAPI应该只知道来自Core的服务。在核心中,我有返回DTO的公共类(服务),但这些服务依赖于我想标记为
内部的DbContext。我当然不能

错误CS0051可访问性不一致:参数类型 “DevicesDbContext”的可访问性不如方法 'DeviceService.DeviceService(DevicesDbContext,IMapper)'

我正在使用EF Core和。我有实体模型,我只能在核心项目中使用。你能告诉我怎样才能做到吗

例如,我的模型是:

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

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

我在DeviceService的构造函数中发现了这个错误。这不是一个错误,因为我知道错误的含义以及如何修复它。在这里,我询问了这种方法的设计或体系结构,因为我需要避免直接在WebAPI中使用模型和dbcontext

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

实体框架是一个框架。它的目的是方便数据访问,使代码更易于编写和理解。正如您选择使用.Net框架并利用Linq、泛型等功能一样,通过选择EF,您应该寻求利用它提供的所有功能

如果您必须将上下文和实体排除在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.
    }
}
公共接口等轴测服务
{
IEnumerable GetSome(/*params*/);
}
公共类SomethingService:ISomethingService
{
公共SomethingService(SomeDbContext上下文)
{//Init东西。
}
IEnumerable ISomethingService.GetSome()
{
//买些东西,把DTO还给我。
}
}
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();
    }
}
公共类SomeAPI:isothingservice
{
私有ISomethingService服务{get;set;}
公共SomeAPI(等轴测服务)
{
服务=服务;
}
公共IEnumerable GetSome()
{
return Service.GetSome();
}
}
API的不足之处在于它只是将请求传递给公共服务并转发响应。API不需要实现相同的接口,它可以简单地接受对服务的引用并使用它,传递任何参数以获得它将传递回的DTO


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

我想问一下,为什么要将DeviceDBContext设为内部?在我看来,设备和DeviceDbContext都应该是公共的。其次,您可以将DTO模型放在新的核心项目中。这可能会让你的责任更加明显。可能尝试将DbContext设置为protected而不是internal?可能重复@ZakkDiaz,我想将其设置为internal,以避免在WebAPI“设计或架构”中直接使用它,这一点有点宽泛。您可能(在中,您应该先阅读他们的帮助中心)可以问这个问题,但我认为,在这里,他们更喜欢对您所寻找的内容进行更具体的说明。@Greg我在核心项目的DI中注册了它。我没有说我想在不注册的情况下注入上下文
public class SomeAPI : ISomethingService
{
    private ISomethingService Service { get; set; }
    public SomeAPI(ISomethingService service)
    {
        Service = service;
    }

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