gpt4 book ai didi

c# - 将 Env Conn String 注入(inject) .NET Core 2.0 w/EF Core DbContext 与 Startup prj 不同的类库中并实现 IDesignTimeDbContextFactory

转载 作者:IT王子 更新时间:2023-10-29 04:50:47 26 4
gpt4 key购买 nike

老实说,我不敢相信这有多难......首先是我要达到的要求:

  • 实现 Entity Framework Core 2.0' IDesignTimeDbContextFactory这是 IDbContextFactory重命名以减少开发人员对其功能的混淆
  • 我不想加载 appsettings.json不止一次。一个原因是因为我的迁移在 MyClassLibrary.Data 的域中运行并且没有 appsettings.js该类库中的文件,我将不得不 Copy to Output Directory appsettings.js .另一个原因是它不太优雅。

所以这是我目前可以使用的:

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
using AppContext = Tsl.Example.Data.AppContext;

namespace Tsl.Example
{
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<AppContext>
{
public AppContext CreateDbContext(string[] args)
{
string basePath = AppDomain.CurrentDomain.BaseDirectory;

string envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{envName}.json", true)
.Build();

var builder = new DbContextOptionsBuilder<AppContext>();

var connectionString = configuration.GetConnectionString("DefaultConnection");

builder.UseMySql(connectionString);

return new AppContext(builder.Options);
}
}
}

这是我的 Program.cs:

using System.IO;
using System.Reflection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace Tsl.Example
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}

//public static IWebHost BuildWebHost(string[] args) =>
// WebHost.CreateDefaultBuilder(args)
// .UseStartup<Startup>()
// .Build();

/// <summary>
/// This the magical WebHost.CreateDefaultBuilder method "unboxed", mostly, ConfigureServices uses an internal class so there is one piece of CreateDefaultBuilder that cannot be used here
/// https://andrewlock.net/exploring-program-and-startup-in-asp-net-core-2-preview1-2/
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public static IWebHost BuildWebHost(string[] args)
{
return new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
IHostingEnvironment env = hostingContext.HostingEnvironment;

config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

if (env.IsDevelopment())
{
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly != null)
{
config.AddUserSecrets(appAssembly, optional: true);
}
}

config.AddEnvironmentVariables();

if (args != null)
{
config.AddCommandLine(args);
}
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
})
//.UseIISIntegration()
.UseDefaultServiceProvider((context, options) =>
{
options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
})
.UseStartup<Startup>()
.Build();
}
}
}

这是我的 Startup.cs:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using ServiceStack;
using Tsl.Example.Interfaces;
using Tsl.Example.Provider;
using AppContext = Tsl.Example.Data.AppContext;

namespace Tsl.Example
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IAppContext, AppContext>();
services.AddTransient<IExampleDataProvider, ExampleDataProvider>();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseServiceStack(new AppHost());
}
}
}

我想做的是使用 IOptions pattern ,所以我创建了这个类:

namespace Tsl.Example
{
/// <summary>
/// Strongly typed settings to share in app using the .NET Core IOptions pattern
/// https://andrewlock.net/how-to-use-the-ioptions-pattern-for-configuration-in-asp-net-core-rc2/
/// </summary>
public class AppSettings
{
public string DefaultConnection { get; set; }
}
}

将此行添加到 Startup.ConfigureServices :

  services.Configure<AppSettings>(options => Configuration.GetSection("AppSettings").Bind(options));

然后尝试更改我对 IDesignTimeDbContextFactory<AppContext> 的实现到:

public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<AppContext>
{
private readonly AppSettings _appSettings;

public DesignTimeDbContextFactory(IOptions<AppSettings> appSettings)
{
this._appSettings = appSettings.Value;
}

public AppContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<AppContext>();
builder.UseMySql(_appSettings.DefaultConnection);
return new AppContext(builder.Options);
}
}

不幸的是,这没有用,因为 Ioptions<AppSettings> public DesignTimeDbContextFactory(IOptions<AppSettings> appSettings) 的参数未注入(inject)构造函数。我认为这是因为 IDesignTimeDbContextFactory<AppContext> 的实现在设计时被调用,而依赖注入(inject)在设计时在 .NET Core 应用程序中还没有“准备好”?

我认为使用 Entity Framework Core 2.0 模式实现 IDesignTimeDbContextFactory 注入(inject)特定于环境的连接字符串是如此困难,这有点奇怪。 ,也不必复制和加载设置文件,如 appsettings.json不止一次。

最佳答案

如果您正在寻找从您的自定义设置类中获取数据库连接字符串的解决方案,该自定义设置类是从 appsettings.json 文件初始化的 - 您可以这样做。不幸的是,您无法通过 DIIOptions 注入(inject)到您的 IDesignTimeDbContextFactory 实现构造函数中。

public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<AppContext>
{
public AppContext CreateDbContext(string[] args)
{
// IDesignTimeDbContextFactory is used usually when you execute EF Core commands like Add-Migration, Update-Database, and so on
// So it is usually your local development machine environment
var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

// Prepare configuration builder
var configuration = new ConfigurationBuilder()
.SetBasePath(Path.Combine(Directory.GetCurrentDirectory()))
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile($"appsettings.{envName}.json", optional: false)
.Build();

// Bind your custom settings class instance to values from appsettings.json
var settingsSection = configuration.GetSection("Settings");
var appSettings = new AppSettings();
settingsSection.Bind(appSettings);

// Create DB context with connection from your AppSettings
var optionsBuilder = new DbContextOptionsBuilder<AppContext>()
.UseMySql(appSettings.DefaultConnection);

return new AppContext(optionsBuilder.Options);
}
}

当然,在您的 AppSettings 类和 appsettings.json 中,您可以使用更复杂的逻辑来构建连接字符串。例如,像这样:

public class AppSettings
{
public bool UseInMemory { get; set; }

public string Server { get; set; }
public string Port { get; set; }
public string Database { get; set; }
public string User { get; set; }
public string Password { get; set; }

public string BuildConnectionString()
{
if(UseInMemory) return null;

// You can set environment variable name which stores your real value, or use as value if not configured as environment variable
var server = Environment.GetEnvironmentVariable(Host) ?? Host;
var port = Environment.GetEnvironmentVariable(Port) ?? Port;
var database = Environment.GetEnvironmentVariable(Database) ?? Database;
var user = Environment.GetEnvironmentVariable(User) ?? User;
var password = Environment.GetEnvironmentVariable(Password) ?? Password;

var connectionString = $"Server={server};Port={port};Database={database};Uid={user};Pwd={password}";

return connectionString;
}
}

仅将值存储在 appsettings.json 中:

{
"Settings": {
"UseInMemory": false,
"Server": "myserver",
"Port": "1234",
"Database": "mydatabase",
"User": "dbuser",
"Password": "dbpassw0rd"
}
}

将密码和用户存储在环境变量中:

{
"Settings": {
"UseInMemory": false,
"Server": "myserver",
"Port": "1234",
"Database": "mydatabase",
"User": "MY-DB-UID-ENV-VAR",
"Password": "MY-DB-PWD-ENV-VAR"
}
}

在这种情况下你应该这样使用它:

// Create DB context with connection from your AppSettings 
var optionsBuilder = new DbContextOptionsBuilder<AppContext>();
if(appSettings.UseInMemory) {
optionsBuilder = appSettings.UseInMemory
? optionsBuilder.UseInMemoryDatabase("MyInMemoryDB")
: optionsBuilder.UseMySql(appSettings.BuildConnectionString());

return new AppContext(optionsBuilder.Options);

关于c# - 将 Env Conn String 注入(inject) .NET Core 2.0 w/EF Core DbContext 与 Startup prj 不同的类库中并实现 IDesignTimeDbContextFactory,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46085500/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com