Asp.net .NET核心分层服务中的依赖注入

Asp.net .NET核心分层服务中的依赖注入,asp.net,asp.net-core,dependency-injection,inversion-of-control,repository-pattern,Asp.net,Asp.net Core,Dependency Injection,Inversion Of Control,Repository Pattern,我正在尝试学习IoC和DI,并将其整合到我在Asp.NET Core上的分层webapi项目中,这样我就可以使用SQLite内存数据库伪造数据库上下文,并测试我的服务层的行为 我有几个unitOfWorks,每个都包含存储库。每个数据库一个工作单元。其中一个如下所示: public class GcgcUnitOfWork : IDisposable { private readonly GcgcContext _context; public AssetRepository

我正在尝试学习IoC和DI,并将其整合到我在Asp.NET Core上的分层webapi项目中,这样我就可以使用SQLite内存数据库伪造数据库上下文,并测试我的服务层的行为

我有几个unitOfWorks,每个都包含存储库。每个数据库一个工作单元。其中一个如下所示:

public class GcgcUnitOfWork : IDisposable
{

    private readonly GcgcContext _context;
    public AssetRepository assetRepository;

    public GcgcUnitOfWork(GcgcContext context)
    {
        _context = context;
        assetRepository = new AssetRepository(_context);
    }

    public int Complete()
    {
        try
        {
            return _context.SaveChanges();
        }
        catch (Exception ex)
        {
            return 0;
        }


    }

    public void Dispose()
    {
        _context.Dispose();
    }
}
public class GcgcService : IGcgcService
{

    public GcgcAssetDataDTO GetGcgcAssetData()
    {
        using (var uow = new GcgcUnitOfWork())
        using (var uowLandornet = new LandornetUnitOfWork())
        {
            var result = new GcgcAssetDataDTO();                                       
            /**do something.*/

            return result;
        }               
    }
}
public class AssetService
{
  GcgcUnitOfWork _uow;
  LandornetUnitOfWork _uow2;

public AssetService(GcgcUnitOfWork uow, LandornetUnitOfWork uow2)
{
    _uow = uow;
    _uow2 = uow2;
}

public List<GcgcAsset> GetAssets()
{

    return _uow.assetRepository.GetAssets();
}

/*also use and interact with other service classes that use these unit of works as well*/
}
在我的服务层上,我使用这些工作单元。一些服务类与两个不同的工作单元交互。如下所示:

public class GcgcUnitOfWork : IDisposable
{

    private readonly GcgcContext _context;
    public AssetRepository assetRepository;

    public GcgcUnitOfWork(GcgcContext context)
    {
        _context = context;
        assetRepository = new AssetRepository(_context);
    }

    public int Complete()
    {
        try
        {
            return _context.SaveChanges();
        }
        catch (Exception ex)
        {
            return 0;
        }


    }

    public void Dispose()
    {
        _context.Dispose();
    }
}
public class GcgcService : IGcgcService
{

    public GcgcAssetDataDTO GetGcgcAssetData()
    {
        using (var uow = new GcgcUnitOfWork())
        using (var uowLandornet = new LandornetUnitOfWork())
        {
            var result = new GcgcAssetDataDTO();                                       
            /**do something.*/

            return result;
        }               
    }
}
public class AssetService
{
  GcgcUnitOfWork _uow;
  LandornetUnitOfWork _uow2;

public AssetService(GcgcUnitOfWork uow, LandornetUnitOfWork uow2)
{
    _uow = uow;
    _uow2 = uow2;
}

public List<GcgcAsset> GetAssets()
{

    return _uow.assetRepository.GetAssets();
}

/*also use and interact with other service classes that use these unit of works as well*/
}
但是现在,为了测试服务层的行为,我需要将数据库上下文注入存储库到服务层构造函数中。因此,我需要更改为如下内容:

public class GcgcUnitOfWork : IDisposable
{

    private readonly GcgcContext _context;
    public AssetRepository assetRepository;

    public GcgcUnitOfWork(GcgcContext context)
    {
        _context = context;
        assetRepository = new AssetRepository(_context);
    }

    public int Complete()
    {
        try
        {
            return _context.SaveChanges();
        }
        catch (Exception ex)
        {
            return 0;
        }


    }

    public void Dispose()
    {
        _context.Dispose();
    }
}
public class GcgcService : IGcgcService
{

    public GcgcAssetDataDTO GetGcgcAssetData()
    {
        using (var uow = new GcgcUnitOfWork())
        using (var uowLandornet = new LandornetUnitOfWork())
        {
            var result = new GcgcAssetDataDTO();                                       
            /**do something.*/

            return result;
        }               
    }
}
public class AssetService
{
  GcgcUnitOfWork _uow;
  LandornetUnitOfWork _uow2;

public AssetService(GcgcUnitOfWork uow, LandornetUnitOfWork uow2)
{
    _uow = uow;
    _uow2 = uow2;
}

public List<GcgcAsset> GetAssets()
{

    return _uow.assetRepository.GetAssets();
}

/*also use and interact with other service classes that use these unit of works as well*/
}
公共类资产服务
{
GcgcUnitOfWork_uow;
LandornetUnitOfWork_uow2;
公共资产服务(GcgcUnitOfWork uow、LandornetUnitOfWork uow2)
{
_uow=uow;
_uow2=uow2;
}
公共列表GetAssets()
{
返回_uow.AssetPository.GetAssets();
}
/*还可以使用使用这些工作单元的其他服务类并与之交互*/
}
因此,在我的测试项目中,我可以使用内存数据库db上下文中的工作单元实例化服务类。但是using语句呢?我将如何处理这件事?有没有人经历过我面临的类似问题?你认为还有另一种更好的方法来构建系统吗


谢谢您,祝您愉快

您的问题不清楚,但一般来说,您的存储库/工作单元应该实现一个接口。然后,只注入接口。这允许您在
ConfigureServices
中为这些接口在不同的实现中进行sub

然而,这里有几个关键问题。首先,不要将您的EF核心上下文包装到存储库/工作单元中。EF是一个ORM,因此,它已经实现了存储库(
DbSet
)和工作单元(
DbContext
)模式。如果您按照自己的存储库和工作单元的自然结论,实现所有可能的功能,那么除了重新创建EF之外,您将什么也不做。当您使用ORM(如EF)时,实际上您选择使用第三方DAL,因此,除此之外创建自己的DAL层是没有意义的

您可能会争辩说,您仍然希望对EF进行抽象,但在您的服务类中已经有了这种抽象。这些应该直接利用您的上下文,存储库和工作单元应该被扔进垃圾箱


其次,看到类似于
公共资产服务(GcgcUnitOfWork uow,LandornetUnitOfWork uow2)
的内容立即告诉我,该类已被破坏。一个工作单元应该封装整个子域,如果您随后注入其中的两个子域,这意味着您的服务类正在处理两个不同的子域,因此做的太多了。一个类应该只做一件事并且做得很好。

在完整方法中,返回1表示成功,0表示失败。不要那样做!您正在丢失有价值的异常信息!让异常冒泡到代码可以处理它的程度。并删除catch块中无用的if块。
getgcassetdata
方法使用无参数构造函数创建
GcgcUnitOfWork
,但如图所示的
GcgcUnitOfWork
类只有一个带参数的构造函数。这使得我们很难理解问题是什么。代码到底是什么样子的?谢谢你的解释。使用存储库是一个有争议的话题。我不在数据访问层测试代码。所以我不测试存储库。在这种情况下,我认为我不需要存储库的接口。我试图完成的是,我想通过内存中的模拟数据库将这些工作单元传递到我的服务层,这样我就可以测试服务层的行为。事实并非如此。该模式的存在只是为了从域中抽象持久性。EF已经做到了,让我换一种说法。我使用存储库将db操作与业务逻辑分开。我可以使用project.DATA之类的东西来代替repository,实际的DB操作由EF抽象,EF也有自己的存储库层。如果您谈论的是持久性的整体概念,那么您的服务将涵盖这一点。在这两种情况下,您的存储库层都是多余的抽象,只会增加更多的维护和测试问题,没有任何好处。因此,服务层是内容包含业务逻辑的地方。考虑到这一点,我认为直接向服务层公开db上下文不是一个好主意。当然,这取决于上下文和项目。但是如果我这样做,将会有大量代码重复,不同的服务共享相同的数据库操作。因此,封装dbcontext是个好主意,不管它是存储库还是自定义数据类。