在Asp.Net Core中动态更改连接字符串
我想在控制器中更改sql连接字符串,而不是在ApplicationDbContext中。 我正在使用Asp.Net Core和Entity Framework Core。
例如:
public class MyController : Controller { private readonly ApplicationDbContext _dbContext public MyController(ApplicationDbContext dbContext) { _dbContext = dbContext; } private void ChangeConnectionString() { // So, what should be here? } }
我怎样才能做到这一点?
我们有一个类似于你的案例。 我们所做的是在Startup类的ConfigureServices方法中使用IServiceCollection的implementationfactory重载,如下所示:
//First register a custom made db context provider services.AddTransient(); //Then use implementation factory to get the one you need services.AddTransient(provider => provider.GetService ().CreateApplicationDbContext());
我现在很难为你实现CreateApplicationDbContext,因为它完全取决于你想要什么。 但是,一旦你确定了你想要如何完成它的部分,该方法的基础知识应该是这样的:
public ApplicationDbContext CreateApplicationDbContext(){ //TODO Something clever to create correct ApplicationDbContext with ConnectionString you need. }
实现此function后,您可以像在构造函数中一样在控制器中注入正确的ApplicationDbContext:
public MyController(ApplicationDbContext dbContext) { _dbContext = dbContext; }
或者控制器中的动作方法:
public IActionResult([FromServices] ApplicationDbContext dbContext){ }
无论你实现细节,诀窍是实现工厂将在每次注入时构建ApplicationDbContext。
告诉我您是否需要更多帮助来实施此解决方案。
更新#1 Yuriy N.询问AddTransient和AddDbContext之间有什么区别,这是一个有效的问题……事实并非如此。 让我解释。
这与原始问题无关。
但是……话虽如此,实施自己的“实施工厂”(这是我要回答的最重要的事情),在这种情况下,entity framework可能比我们需要的更棘手。
但是,通过这些问题,我们现在可以幸运地查看GitHub中的源代码,因此我查看了AddDbContext的确切function。 好吧……那真的不难。 这些’add’(和’use’)扩展方法只不过是方便方法,请记住。 因此,您需要添加AddDbContext所做的所有服务以及选项。 也许您甚至可以重用AddDbContext扩展方法,只需在实现工厂中添加自己的重载。
所以,回到你的问题。 AddDbContext执行一些EF特定的东西。 正如您所看到的,它们将允许您在以后的版本中使用一生(瞬态,单例)。 AddTransient是Asp.Net Core,允许您添加所需的任何服务。 而且你需要一个实施工厂。
这会让它更清楚吗?
我可以通过将连接字符串逻辑移动到OnConfiguring
方法来更改每个请求的连接字符串。
在Startup.cs#ConfigureServices
services.AddDbContext
方法: services.AddDbContext
在MyDbContext.cs中,我添加了我需要注入构造函数的服务。
private IConfigurationRoot _config; private HttpContext _httpContext; public MyDbContext(DbContextOptions options, IConfigurationRoot config, IHttpContextAccessor httpContextAccessor) : base(options) { _config = config; _httpContext = httpContextAccessor.HttpContext; }
然后重写OnConfiguring:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var connString = BuildConnectionString(); // Your connection string logic here optionsBuilder.UseSqlServer(connString); }
如果要根据活动的http请求的参数为每个http请求选择一个连接字符串,这就足够了。
using Microsoft.AspNetCore.Http; //.. services.TryAddSingleton(); services.AddDbContext((serviceProvider, options) => { var httpContext = serviceProvider.GetService().HttpContext; var httpRequest = httpContext.Request; var connection = GetConnection(httpRequest); options.UseSqlServer(connection); });
您无法轻松访问用户,也无法获得他的声明。 除非你手动完成。
如何从令牌中提取并获得声明?
这对我有用:
public void ConfigureServices(IServiceCollection services) { // ..... services.TryAddSingleton(); services.AddTransient(provider => { return ResolveDbContext(provider, hostingEnv); }); // .. } private MyDbContext ResolveDbContext(IServiceProvider provider, IHostingEnvironment hostingEnv) { string connectionString = Configuration.GetConnectionString("DefaultConnection"); string SOME_DB_IDENTIFYER = httpContextAccessor.HttpContext.User.Claims .Where(c => c.Type == "[SOME_DB_IDENTIFYER]").Select(c => c.Value).FirstOrDefault(); if (!string.IsNullOrWhiteSpace(SOME_DB_IDENTIFYER)) { connectionString = connectionString.Replace("[DB_NAME]", $"{SOME_DB_IDENTIFYER}Db"); } var dbContext = new DefaultDbContextFactory().CreateDbContext(connectionString); // .... return dbContext; }
@ginalx和@jcmordan的答案非常适合我的用例。 我喜欢这些答案的是我可以在Startup.cs
完成所有操作并保持所有其他类清除构造代码。 我想为Web Api请求提供一个可选的查询字符串参数,并将其替换为创建DbContext的基本连接字符串。 我将基本字符串保存在appsettings.json中,并根据传入的参数对其进行格式化,如果没有提供,则将其格式化,即:
"IbmDb2Formatted": "DATABASE={0};SERVER=servername;UID=userId;PWD=password"
对我来说,最终的ConfigureServices
方法看起来像(obvs。我连接到DB2而不是SQL,但这是偶然的):
public void ConfigureServices(IServiceCollection services) { services.AddTransient(); services.AddDbContext(((serviceProvider, options) => { var httpContext = serviceProvider.GetService().HttpContext; var httpRequest = httpContext.Request; // Get the 'database' querystring parameter from the request (if supplied - default is empty). // TODO: Swap this out for an enum. var databaseQuerystringParameter = httpRequest.Query["database"].ToString(); // Get the base, formatted connection string with the 'DATABASE' paramter missing. var db2ConnectionString = Configuration.GetConnectionString("IbmDb2Formatted"); if (!databaseQuerystringParameter.IsNullOrEmpty()) { // We have a 'database' param, stick it in. db2ConnectionString = string.Format(db2ConnectionString, databaseQuerystringParameter); } else { // We havent been given a 'database' param, use the default. var db2DefaultDatabaseValue = Configuration.GetConnectionString("IbmDb2DefaultDatabaseValue"); db2ConnectionString = string.Format(db2ConnectionString, db2DefaultDatabaseValue); } // Build the EF DbContext using the built conn string. options.UseDb2(db2ConnectionString, p => p.SetServerInfo(IBMDBServerType.OS390)); })); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Title = "DB2 API", Version = "v1" }); }); }
- 在ASP.NET中异步发送电子邮件的正确方法…(我做得对吗?)
- 在HttpHandler中通过Windows API生成图像的Thumnail
- FormsAuthentication.SetAuthCookie()是否需要重定向?
- 在c#中使用“using”关键字
- 尝试从Web应用程序访问报告服务时,Internet Explorer会导致IIS 500错误
- 为什么没有asp.net 5.0预览的身份validation – web api模板 –
- document.getElementById(’id’)。值在ASP.net javascript函数中失败
- entity framework:如何表达包含的LIKE语句
- 如何检查控件是否是另一个控件的子控件? “Control.IsChildOf”