如何在我的 DbContext 中获取 IConfiguration 实例?
Posted
技术标签:
【中文标题】如何在我的 DbContext 中获取 IConfiguration 实例?【英文标题】:How do I get an IConfiguration instance in my DbContext? 【发布时间】:2020-08-27 16:20:32 【问题描述】:我见过很多 tutorials 解释 .NET core + EF 配置,但没有一个解释如何在 DbContext
中获取 Configuration
实例。
我需要这个的原因是为了获取数据库连接字符串:
namespace Models
public class BlogContext : DbContext
public DbSet<Blog> Blogs get; set;
public DbSet<Post> Posts get; set;
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite(Configuration.GetConnectionString("BlogDb"));
我的连接字符串在appsettings.json
文件中:
"ConnectionStrings":
"BlogDB": "Data Source=blogging.db"
大多数教程在 db 上下文中显示IConfiguration
的实例。我怀疑它是通过构造函数发生的:
private readonly IConfiguration Configuration;
public BlogContext(IConfiguration config)
Configuration = config;
但是,这实际上是如何注入的?
这就是我使用上下文的方式:
public class Seed
public static void SeedDatabase()
using var db = new BlogContext();
... stuff ...
我如何真正从设置文件中获取连接字符串?做一些非常简单的事情似乎很混乱,需要做很多工作......
更新
我像这样使用Seed
:
public class Program
public static void Main(string[] args)
Seed.SeedDatabase();
我如何真正将DbContext
的实例放入SeedDatabase
?
【问题讨论】:
【参考方案1】:根据上面的代码,看起来在依赖注入和静态代码上可能存在一些混合和匹配,这让你很头疼。您的中间示例期望配置通过构造函数注入进入,但随后您在无法使用它的静态方法中新建了一个实例。
理想情况下,在您的服务注册期间,您应该执行以下操作:
services.AddDbContext<BlogContext>(options =>
options.UseSqlite(Configuration.GetConnectionString("BlogDb")));
这是将 DB 上下文注册到服务容器中,并设置了选项委托以使用来自 appsettings 的连接字符串,因此您的上下文将如下所示:
public BlogContext(DbContextOptions<BlogContext> options)
: base(options)
// ...
而且您的上下文不再直接依赖 IConfiguration 对象。此处的 Microsoft 文档中有一个示例:
https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext#using-dbcontext-with-dependency-injection
不过,无论使用哪种路由,您都需要由 DI 容器注入 DbContext 以解析依赖关系树,因此尝试在静态方法中新建上下文是行不通的——您必须以某种方式获得那种依赖(因此你的问题)。如果我没看错的话,这里有一点 XY 问题,所以我会尝试涵盖两者。
如果您确实需要维护所编写的代码,您可以将 IConfiguration 注入到 Seed 类(或您从中调用的任何其他类)中,然后通过方法注入将其传递给静态方法。 Seed 类本身(或任何其他实例化的类)必须注册到 DI 容器,以便将 IConfiguration 传递给它自己的构造函数,然后在您使用它的地方注入:
public class Seed
private readonly IConfiguration _configuration;
// The Seed instance itself could have the IConfiguration injected and be available to pass to the static method...
public Seed(IConfiguration configuration)
_configuration = configuration;
// ... but either way, when you call this, you have to pass in the dependency yourself, either from this class's instance, or from another one
public static void SeedDatabase(IConfiguration configuration)
using (var db = new BlogContext(configuration))
//...
更实际的是,您似乎正在尝试为数据库播种(duh)。如果是这种情况,请查看 EF Core 的播种机制:https://docs.microsoft.com/en-us/ef/core/modeling/data-seeding
更新 根据您发布的附加代码添加一些进一步的信息。在您的示例中,您正试图在程序的入口点点击您的静态种子函数。仍然很难从代码中判断您是否正在构建主机和服务容器,所以我现在假设不是。您可以尝试以下方法:
using System;
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
public class Program
public static void Main(string[] args)
var configuration = new ConfigurationBuilder()
.AddJsonFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json")) // Grabs the appsettings JSON as the configuration source
.Build();
var dbOptions = new DbContextOptionsBuilder<BlogContext>()
.UseSqlite(configuration.GetConnectionString("BlogDb"));
Seed.SeedDatabase(new BlogContext(dbOptions)); // Pass in your prepared DbContext via method injection
//...
EF Core 种子功能可能仍会帮助您获得更强大的功能。
【讨论】:
在注册期间配置连接字符串听起来像是要走的路。但是我仍然不知道IConfiguration
实例的来源。看起来services.AddDbContext
在Startup.cs
中。如何在其中获取 IConfig 的实例??
Startup.cs
是 ASP NET Core 默认为您启动的主机构建器进程的一部分。当您在程序入口点的Program.cs
期间执行CreateDefaultBuilder
步骤时,它会运行几个步骤,从几个不同的地方组装该配置,然后将其注入到 Startup 类中。这里有一些关于来源的更多细节:docs.microsoft.com/en-us/aspnet/core/fundamentals/host/…——这个行为可以自定义,但是你的 appsettings.json 是默认加载的
我明白了。我如何才能真正将 DbContext 的实例放入依赖类?如果我要新建一个 Seed
的实例,我需要从 DI 寄存器中获取 DbContext
,或者手动创建一个新实例并将其传入。我该怎么做?
我根据您的更新在我的答案中添加了一些额外的内容。由于您在入口点显示调用此权限,因此主机构建器和服务注册代码都没有运行(假设您正在这样做),因此没有可从中获取或注入 DbContext 的容器。如果这是您需要运行它的地方,您可以通过 ConfigurationBuilder 启动一个新配置并获取您需要的内容。【参考方案2】:
您也应该使用带有注入的 DbContext。请注意,任何要注入的东西都需要作为服务添加。您通常可以从Startup
类中添加一个类作为服务。对于 DbContext,您将在 ConfigureServices
方法中使用扩展方法 AddDbContext
。
services.AddDbContext<BlogContext>();
一旦你使用上面的这段代码,你就可以按照你尝试的方式注入IConfiguration
。
但是这不是设置网络应用程序时的最佳做法。 IConfiguration
一般只用在启动类中。在这种情况下,您可以将参数传递给AddDbContext
函数以添加配置。
services.AddDbContext<BloggingContext>(options => options.UseSqlite(Configuration.GetConnectionString("BlogDb"));
如果你使用这个方法,你还应该记得使用下面的构造函数:
public class BlogContext : DbContext
public BlogContext(DbContextOptions<BlogContext> options)
:base(options)
public DbSet<Blog> Blogs get; set;
有关此过程的完整文档,请查看此链接:https://docs.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext。
数据播种也内置在 EF Core 中。你可以检查这个: https://docs.microsoft.com/en-us/ef/core/modeling/data-seeding
【讨论】:
我如何真正让 DbContext 在某处使用?【参考方案3】:在你的种子类中的某个地方:
var config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddEnvironmentVariables()
.Build();
var dbContext = new DbContext(config);
【讨论】:
以上是关于如何在我的 DbContext 中获取 IConfiguration 实例?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 EF7 DbContext 获取 ConnectionString
我可以在我的 Web API 中调用 DBContext.SaveChangesAsync 并假设此任务将在我的方法返回时继续吗?
如何将参数传递给 DbContext.Database.ExecuteSqlCommand 方法?
如何在静态方法或控制器外的类中获取applicationDbContext的dbContext