繁体   English   中英

在单个解决方案中跨不同项目重用 DbContext 的正确方法是什么?

[英]What is the proper way to reuse DbContext across different projects in a single solution?

我有一个 .Net Core 解决方案,它由 3 个项目组成,如下所示:

  1. 通用:(所有 EF 数据、迁移、模型、DbContext)
  2. WebApi :(Rest api 使用来自 Common 的 DbContext)
  3. Worker :(旨在从 Common 消费 DbContext 的后台服务)

我想将我所有的 EF 逻辑和 DbContext 放在 Common 中,并从我的其他两个项目中使用它。 WebApi 工作正常,但我无法从 Worker 项目中的托管服务中使用它。 有 4 个后台工作人员,他们都需要访问数据库,所以我想访问他们内部的 DbContext。

那么,跨多个项目重用 DbContext 的正确方法是什么。 可以认为所有的服务都需要访问一些公共的表。 所以通过不同的 Dbcontexts 隔离表对我来说不是一个选择。

这是我在 WebApi 中的 Startup.cs:

services.AddDbContext<DataContext>(options => options
        .UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));

这是我在 Worker 中的 Program.cs:

services.AddDbContext<DataContext>(options => options
        .UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));

它抛出一个错误,告诉我我不能从单例服务中使用范围服务。

如果您只想在 Web API + 后台工作人员中引用 DbContext,那么我不明白问题是什么:只需从您的工作人员项目中引用 Common 项目即可。 从您的帖子来看,问题似乎是您在 Web API 中成功使用的服务注入不适用于后台工作程序服务。 (假设 Windows 服务?)

从更简单的场景开始。 使用时在服务内部启动 DbContext,而不是注入它。

IE

using(var context = new DataContext("DefaultConnection"))
{
    // ...
}

您的连接字符串配置应该将 NPGSQL 标识为提供者,只要该配置在您的服务配置中全部设置,那么 DBContext 应该能够通过连接字符串名称进行配置。 如果那行得通,那么可能会有不同的注入机制。 从我很快发现的情况来看,似乎示例使用服务定位器模式来解决依赖关系,我不知道现在是否有更好的 Windows 服务选项。

如果注入不是一个真正的选择,并且您必须求助于类似服务定位器的实现,那么我可能会考虑像我过去使用过的惰性属性注入模式之类的东西:

public class WorkerService
{
    private readonly IContainer _container = null;

    public WorkerService(IContainer container)
    {
        _container = container ?? throw new ArgumentNullException("container");
    }

    private IDataContextFactory _contextFactory = null;
    public IDataContextFactory ContextFactory
    {
        get { return _contextFactory ?? (_contextFactory = _container.Resolve<IDataContextFactory>()); }
        set { _contextFactory = value; }
    }

    public void Execute()
    {
         using(var context = ContextFactory.Create()) // returns a DataContext.
         {
             // do stuff.
         }
    }

}

其中IContainer代表给定 DI 框架的契约接口。 (Unity、Autofac 等)

或者,用于确定 DbContext 范围的工作单元。 给定一个服务实例将长时间运行,我们不想注入或解析 DbContext,而是一个上下文工厂,我们可以使用它来接收可以在处置中使用的初始化 DbContext。 通常对于 web 请求,实例的范围是请求,并在请求结束时由容器处理。 对于服务,我们希望确保定期处理 DbContext。 可以设置 DI 以便返回上下文的瞬态实例,但需要处理这些实例,这意味着它不适合构造函数注入,而是通过服务定位器。 如果在服务的构造函数中使用并注入单个 DbContext 实例,它将一直存在到服务停止为止,这会看到 DbContext 由于跟踪的实体而随着时间的推移变得越来越慢。

我想你在这里有点困惑。 您要重用的是 DbContext 代码 + 所有 EF 逻辑。 您不想(不能)跨项目(应用程序)重用相同的 DbContext 实例。

所以要重用代码,你只需要把你所有的 Model + DBContext 放在一个项目中。 然后在其他项目中,你可以添加对它的引用。 并开始使用它。

从 Startup.cs/Program.cs 中删除所有 AddDbContext。

将 DbContext 连接字符串放在 Common 项目中。

在 Common 项目中创建一些 CRUD。 然后所有其他项目都可以使用连接到相同 DbContext 的 Common CRUD。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM