将配置文件中的连接字符串注入 EF Core DbContext

Injecting Connection String from config file into EF Core DbContext

我需要为我的项目向我的 DbContext Class 注入依赖项。我正在尝试以遵循 "Clean Architecture" 的方式执行此操作。

我需要能够使用 DbContext 的空构造函数并仍然引用配置文件中的连接字符串。

我利用这个通用存储库并将其注入到服务中。它在应用层中定义。

     public class GenericRepository<C, T> : IGenericRepository<C, T> where T : class where C : DbContext, new()
     {
        private DbContext _entities = new C();
     }

在我的 EF Core Context class(在持久层中定义)我有这个:

   public partial class MyContext : DbContext
   {
       private IConnectionStringProvider _connectionStringProvider;  

        public virtual DbSet<MyEntity> { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {  
                optionsBuilder.UseSqlServer(_connectionStringProvider.GetConnectionString());
            }
        }
    }

我还在持久层中定义了 IConnectionStringProvider 的实现。如果需要,我希望这个实现可以很容易地交换。目前它从 App.config 读取并使用 ConfigurationManager nuget 包。但这在未来可能会改变,因此它需要易于交换。

应用层定义了IConnectionStringProvider:

 public interface IConnectionStringProvider
 {
     string GetConnectionString();
 }

在我的表示层中,我有一个 ASP.NET Core MVC 项目。在 StartUp.cs 中,我使用标准方式将 dbContext 注入我的控制器:

services.AddDbContext<ContractsWorkloadContext>();

如果我按以下方式覆盖 OnModelCreatingMethod,我可以让它正常工作。

 protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
 {
     if (!optionsBuilder.IsConfigured)
     {
         _connectionStringProvider = new ConnectionStringProvider();
         optionsBuilder.UseSqlServer(ConnectionStringProvider.GetConnectionString());
     }
 }

此方法允许我使用配置中的连接字符串值和一个空的上下文构造函数实例,这是它与我的通用存储库一起工作所必需的,并且仍然能够使用带有 DbContextOptionsBuilder 参数的构造函数。

我唯一要解决的问题是如何在上下文不依赖于实现的情况下实现这一点。

我已经通过注册 IConnectionStringProvider 接口和实现以及使用属性 "Autowired" 注册上下文 class 来尝试 Autofac 属性 注入。但是 属性 始终为空。

是的,我知道上面是一个字段而不是 属性。我试图修改上下文 class 以使用 属性 而不是字段。我什至尝试创建一种方法来设置字段并使用 autofac 方法注入。但是 property/field 在每种情况下始终为 null。

 builder.RegisterType<ConnectionStringProvider>().As<IConnectionStringProvider>()();
 builder.RegisterType<MyContext>().PropertiesAutowired();

 builder.RegisterType<ContractsWorkloadContext>().OnActivated(e =>
 {
     var provider = e.Context.Resolve<IConnectionStringProvider>();
     e.Instance.SetConnectionstringProvider(provider);
 });

总而言之,我需要:

  1. 将连接字符串注入上下文
  2. 允许创建空的构造函数实例
  3. 维护"Clean Architecture"设计

如有任何帮助,我们将不胜感激。

谢谢。

我最后做的是创建一个对连接字符串的静态引用,然后在 returns 该值的上下文中创建一个只读 属性。

通过这种方式,我能够抽象出应用层中的 IConnectionStringProvider 并在基础结构层中实现它。如果需要,这将允许以最小的努力换出实现。

此外,通过添加 returns 静态连接字符串的只读 属性,我能够使用一个利用 new() 的通用存储库,并且仍然从配置文件。

唯一的缺点是连接字符串在整个应用程序生命周期内都存储在内存中。

静态值由表示层 StartUp.cs 文件中的提供程序实现设置。

这绝对有效...但如果有更好的方法,我会洗耳恭听...:)

这是一个更好的方法...对于任何偶然发现此方法的人...

更具体的存储库实现只是 类 扩展基本存储库实现。如:

EFCustomerRepository : EFRepository<MyContext, Customer>

现在我可以通过依赖项注入在整个应用程序的任何地方注入 IMyEFCoreDatabase 并引用存储在实现中的存储库。

这是比上面更好的方法,因为我的存储库不再调用 new C()。相反,他们现在通过构造函数注入来注入上下文。