问题描述
我正在使用 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 时,您有两个选择:
- 直接在 Simple Injector 中注册
DbContext
。这将让 Simple Injector 管理DbContext
的生命周期。 - 在框架的配置系统中注册
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
中。