如何使用 Entity Framework Core 和 Simple Injector 在 .NET Core WebApi 的 DBContext 中访问 AppSettings.json 文件?

问题描述

我正在使用 Entity Framework Core 和 Simple Injector IoC Container 构建 ASP.NET Core WebApi 服务。 该应用程序通过 Npgsql.EntityFrameworkCore.Postgesql 使用 postgresql 数据库

这是我的启动ServicesInstaller代码片段:

public class Startup
{
    public IConfiguration Configuration { get; }
    private IConfigurationRoot configurationRoot;
    private Container container;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;

        // Build configuration info
        configurationRoot = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json",optional: true,reloadOnChange: true)
            .Build();
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();

        // Initialize Container
        container = new SimpleInjector.Container();
        container.Options.ResolveUnregisteredConcreteTypes = false;
        container.ConfigureServices();
        
        services.AddSimpleInjector(container,options =>
        {
            options.AddAspNetCore()
            .AddControllerActivation();
            options.AddLogging();
        });
    }
}

服务安装程序:

public static class ServicesInstaller
{
    public static void ConfigureServices(this Container container)
    {
        container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

        //Assembly.Load will not re-load already loaded Assemblies
        container.Register<IFooContext,FooContext>(Lifestyle.Scoped);
        container.Register<FooContext>(Lifestyle.Scoped);
    }
}

这是我的 DB Context 类的代码片段:

public interface IFooContext
{
}
    
public class FooContext : DbContext,IFooContext
{
    public FooContext()
    {
    }
    
    protected override void OnConfiguring(
        DbContextOptionsBuilder optionbuilder)
    {
        optionbuilder.UseNpgsql(
            "Server=.;Port=5432;Database=...;User ID=...;Password=...;");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    }
}

目前我正在将我的连接字符串硬连线到 PostGresql DB。我希望能够从数据库上下文中的 AppSettings.json 文件中检索连接字符串。我相信正确的做法应该是在 OnConfiguring() 方法中。

正确吗?

给定这个模型,我该如何正确访问 DBContext 类中的 AppSettings.json 文件

解决方法

在集成 ASP.NET Core icw Simple Injector 和 Entity Framework 时,您有两个选择:

  1. 直接在 Simple Injector 中注册 DbContext。这将让 Simple Injector 管理 DbContext 的生命周期。
  2. 在框架的配置系统中注册 DbContext(即 IServiceCollection)。在这种情况下,DbContext 仍然可以注入到您使用 Simple Injector 进行的其他注册中,因为 Simple Injector 会从框架的配置系统“拉入”(又名交叉线)该依赖项。

在大多数情况下,您应该选择选项 1,因为让 Simple Injector 管理依赖项也允许 Simple Injector 验证和diagnose注册。

由于 Entity Framework 和 .NET Core 配置系统之间的耦合,选项 1 可以更容易实现。这反映在 Simple Injector 文档中。它states

然而,在某些情况下,框架和第三方组件与这个新的配置系统紧密耦合。 Entity Framework 的 DbContext 池化特性就是引入这种紧密耦合的一个例子——池化实际上只能通过在 Microsoft 的 IServiceCollection 中进行配置来使用。然而,作为应用程序开发人员,您希望使用 Simple Injector 来组合您的应用程序组件。但是这些应用组件需要不时地与那些框架和第三方服务一起提供,这意味着需要从 .NET 配置系统中拉入框架组件。

这意味着您可以遵循有关注册 DbContext 的所有 Microsoft 文档。例如,您可以按如下方式注册您的 DbContext

// For the full example,see: https://simpleinjector.org/aspnetcore
public class Startup
{
    private Container container = new SimpleInjector.Container();

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        // ASP.NET default stuff here
        services.AddControllers();

        services.AddLogging();

        services.AddSimpleInjector(container,options =>
        {
            options.AddAspNetCore()
                .AddControllerActivation();

            options.AddLogging();
        });
        
        // Add DbContext to IServiceCollection using AddDbContext.
        services.AddDbContext<FooContext>(
            options => options.UseNpgsql(
                "Server=.;Port=5432;Database=...;User ID=...;Password=...;"));

        InitializeContainer();
    }

    private void InitializeContainer()
    {
        // Register all other classes using SImple Injector here. e.g.:
        container.Register<ITimeProvider,TimeProvider>(Lifestyle.Singleton);
    }

    public void Configure(IApplicationBuilder app,IWebHostEnvironment env)
    {
        app.UseSimpleInjector(container);

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");
        });

        container.Verify();
    }
}

由于 Simple Injector 具有跨线依赖的能力,您仍然可以将 FooContext 注入到 Simple Injector 中注册和创建的任何类中。

注意:即使您将 FooContext 注册到 IServiceCollection 中,也要确保在 Simple Injector 中注册尽可能多的类。当使用 Simple Injector 作为您选择的 DI 容器时,您的所有应用程序组件都应该注册到 Simple Injector 中。 DbContext 是罕见的例外。但是,框架组件仍应注册到 IServiceCollection 中。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...