【问题标题】:Dependency Injection in .NET core layered services.NET 核心分层服务中的依赖注入
【发布时间】:2020-01-17 07:39:05
【问题描述】:

我正在尝试学习 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;
        }               
    }
}

但是现在,为了测试服务层的行为,我需要将带有 db 上下文的存储库注入到服务层的构造函数中。所以我需要更改为如下内容:

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*/
}

所以在我的测试项目中,我可以使用内存数据库数据库上下文的工作单元来实例化服务类。但是 using 语句呢?我将如何处理?有人遇到过我面临的类似问题吗?您认为还有其他更好的方法来构建系统吗?

谢谢你,祝你有美好的一天

【问题讨论】:

  • 在您的 Complete 方法中,您返回 1 表示成功,返回 0 表示失败。不要那样做!您正在丢失有价值的异常信息!让异常冒泡到代码可以对其进行处理的程度。并删除你的 catch 块中无用的 if 块。
  • GetGcgcAssetData 方法使用无参数构造函数创建 GcgcUnitOfWork,但所示的 GcgcUnitOfWork 类只有一个带参数的构造函数。这使得很难理解问题是什么。代码到底是什么样子的?

标签: asp.net asp.net-core dependency-injection inversion-of-control repository-pattern


【解决方案1】:

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

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

您可能会争辩说您仍然希望对 EF 进行抽象,但您的服务类中已经有了它。那些应该直接利用您的上下文,并且存储库和工作单元应该被丢弃。

其次,看到public AssetService(GcgcUnitOfWork uow, LandornetUnitOfWork uow2) 之类的内容会立即告诉我,这门课坏了。一个工作单元应该封装整个子域,如果您要注入其中两个,这意味着您的服务类正在使用两个不同的子域,因此做得太多。一个班级应该只做一件事并把它做好。

【讨论】:

  • 感谢您的解释。使用存储库是一个值得商榷的话题。我不测试数据访问层中的代码。所以我不测试存储库。在这种情况下,我认为我不需要存储库的接口。我想要完成的是,我想将这些工作单元传递到我的服务层,使用内存中的模拟数据库,以便我可以测试服务层的行为。
  • 真的不是。该模式的唯一存在是为了从域中抽象持久性。 EF 已经这样做了。
  • 让我换一种说法。我使用存储库将数据库操作与业务逻辑分开。我可以使用 project.DATA 之类的东西来代替存储库。
  • 实际的 DB 操作由 EF 抽象出来,EF 又拥有自己的存储库层。如果您在谈论一般持久性的整个想法,那么您的服务将涵盖这一点。在任何一种情况下,您的存储库层都是多余的抽象,只会增加更多的维护和测试问题而没有任何好处。
  • 嗨,克里斯,很抱歉这么晚才回复你。所以服务层是包含业务逻辑的地方。我考虑了这一点,我认为将 db 上下文直接暴露给服务层并不是一个好主意。当然,这取决于上下文和项目。但是如果我这样做,将会有很多代码重复并且不同的服务共享相同的数据库操作。因此,出于这个原因,封装 dbcontext 是个好主意,无论它是存储库还是自定义数据类。
猜你喜欢
  • 2018-12-14
  • 2019-01-31
  • 2019-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-02
  • 1970-01-01
相关资源
最近更新 更多