简体   繁体   English

如何在我的 DbContext 中获取 IConfiguration 实例?

[英]How do I get an IConfiguration instance in my DbContext?

I've seen a number of tutorials that explain .NET core + EF configuration, but none of them explain how to get a Configuration instance in the DbContext .我看过许多解释 .NET 核心 + EF 配置的教程,但没有一个解释如何在DbContext中获取Configuration实例。

The reason I need this is to get the db connection string:我需要这个的原因是获取数据库连接字符串:

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"));

    }
}

My connection string is in an appsettings.json file:我的连接字符串在appsettings.json文件中:

{
    "ConnectionStrings": {
        "BlogDB": "Data Source=blogging.db"
    }
}

Most tutorials show an instance of IConfiguration in the db context.大多数教程在数据库上下文中显示IConfiguration的实例。 I suspect that it happens through the constructor:我怀疑它是通过构造函数发生的:

private readonly IConfiguration Configuration;
public BlogContext(IConfiguration config) {
    Configuration = config;
}

But, how does this actually get injected?但是,这实际上是如何注入的呢?

This is how I'm using the context:这就是我使用上下文的方式:

public class Seed
    {
        public static void SeedDatabase()
        {
            using var db = new BlogContext();
            ... stuff ...
        }
    }

How do I actually get the connection string from the settings file?我实际上如何从设置文件中获取连接字符串? It seems very confusing and a lot of work to do something very simple...做一些非常简单的事情似乎很混乱并且需要做很多工作......

UPDATE更新

I'm using Seed like so:我像这样使用Seed

public class Program
    {
        public static void Main(string[] args)
        {
            Seed.SeedDatabase();
        }
    }

How do I actually get an instance of DbContext into SeedDatabase ?我实际上如何将DbContext的实例放入SeedDatabase

Based on the code above, it looks like there might be some mixing and matching on dependency injected and static code that's giving you a headache.根据上面的代码,看起来依赖注入和 static 代码可能有一些混合和匹配让你头疼。 Your middle example expects the configuration to come in through constructor injection, but then you're newing up an instance in your static method that can't use it.您的中间示例期望配置通过构造函数注入进入,但随后您在 static 方法中更新了一个无法使用它的实例。

Ideally, during your service registration, you'd do something like:理想情况下,在您的服务注册期间,您会执行以下操作:

services.AddDbContext<BlogContext>(options => 
    options.UseSqlite(Configuration.GetConnectionString("BlogDb")));

This is registering the DB context into the service container with the options delegate set up to use the connection string from the appsettings, so your context would just look like:这是将数据库上下文注册到服务容器中,选项委托设置为使用应用程序设置中的连接字符串,因此您的上下文看起来像:

public BlogContext(DbContextOptions<BlogContext> options)
   : base(options)
{
// ... 
}

And your context is no longer directly taking the dependency on the IConfiguration object. There's an example of that in Microsoft's docs here:并且您的上下文不再直接依赖 IConfiguration object。Microsoft 的文档中有一个示例:

https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext#using-dbcontext-with-dependency-injection https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext#using-dbcontext-with-dependency-injection

With either route, though, you'd need to have the DbContext injected by the DI container in order to resolve the dependency tree, so trying to new up a context in the static method isn't working -- you have to get that dependency there somehow (hence your question).但是,无论使用哪种方法,您都需要通过 DI 容器注入 DbContext 才能解析依赖关系树,因此尝试在 static 方法中新建上下文是行不通的——您必须获得该依赖关系不知何故(因此你的问题)。 There's a bit of an XY problem here if I'm reading it right, so I'll try to cover both.如果我没看错的话,这里有一点 XY 问题,所以我会尝试涵盖两者。

If you really need to maintain the code as written, you could inject the IConfiguration into the Seed class (or whatever other class you're calling from) and then pass it down to the static method via method injection.如果您确实需要按照编写的方式维护代码,则可以将 IConfiguration 注入 Seed class(或您调用的任何其他 class),然后通过方法注入将其传递给 static 方法。 The Seed class itself (or whatever other instantiated class) would have to be registered to the DI container in order to get the IConfiguration passed into its own constructor and then injected where you're using it:种子 class 本身(或任何其他实例化类)必须注册到 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))
        {
            //...
        }
    } 

} }

More realistically, it looks like you're trying to seed the database (duh).更现实地说,看起来您正在尝试为数据库播种(duh)。 If that's the case, take a look at EF Core's mechanisms for seeding:https://learn.microsoft.com/en-us/ef/core/modeling/data-seeding如果是这种情况,请查看 EF Core 的播种机制:https://learn.microsoft.com/en-us/ef/core/modeling/data-seeding

UPDATE Adding some further information based on the additional code you posted.更新根据您发布的附加代码添加一些进一步的信息。 In your example, you're trying to hit your static seed function right at the program's entry point.在您的示例中,您正试图在程序的入口点点击 static 种子 function。 Still hard to tell from the code whether you're building a host and service container, so I'll assume not for now.仍然很难从代码中判断您是否正在构建主机和服务容器,所以我暂时假设不会。 You can try something like the following:您可以尝试以下操作:

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

The EF Core seed capabilities will still probably help get you something more robust. EF Core 种子功能可能仍会帮助您获得更强大的功能。

You should be using the DbContext with injection too.您也应该将 DbContext 与注入一起使用。 Note that anything to be injected needs to be added as a service.请注意,任何要注入的东西都需要作为服务添加。 You can generally add a class as a service from the Startup class. In the case of a DbContext, you would use the extension method AddDbContext inside the ConfigureServices method.您通常可以从Startup class 添加 class 作为服务。在 DbContext 的情况下,您将在ConfigureServices方法中使用扩展方法AddDbContext

services.AddDbContext<BlogContext>();

Once you use this code above, you will be able to inject IConfiguration the way you tried.使用上面的代码后,您将能够按照您尝试的方式注入IConfiguration

However this is not the best practice when setting up a web app.但是,这不是设置 web 应用程序时的最佳做法。 The IConfiguration is generally just used in the startup class. In this case, you can pass a parameter into the AddDbContext function to add a configuration. IConfiguration一般只是在启动时使用 class 。此时可以向AddDbContext function 传入一个参数来添加配置。

services.AddDbContext<BloggingContext>(options => options.UseSqlite(Configuration.GetConnectionString("BlogDb"));

If you use this method, you should also remember to use the following constructor:如果使用此方法,还应记住使用以下构造函数:

public class BlogContext : DbContext
{
    public BlogContext(DbContextOptions<BlogContext> options)
    :base(options)
    { }

    public DbSet<Blog> Blogs { get; set; }
}

For the full documentation on this process, check this link: https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext .有关此过程的完整文档,请查看此链接: https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext

Data seeding is also build into EF Core. EF Core 中也内置了数据播种。 You can check this:https://learn.microsoft.com/en-us/ef/core/modeling/data-seeding你可以检查这个:https://learn.microsoft.com/en-us/ef/core/modeling/data-seeding

Somewhere in your Seed class:在你的种子 class 的某处:

var config = new ConfigurationBuilder()
                 .SetBasePath(Directory.GetCurrentDirectory())
                 .AddEnvironmentVariables()
                 .Build();
var dbContext = new DbContext(config);

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

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