.NET核心DbContext动态连接字符串

tun*_*uno 5 .net c# asp.net-mvc entity-framework .net-core

我试图根据每个http请求标头设置我的DbContext的连接字符串.是否有可能在.NET Core中这样做?我在MVC5中做到了,但我无法在.NET核心中实现它.

public void ConfigureServices(IServiceCollection services)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

我不知道http标头,所以我在哪里可以做到?

Fed*_*uma 9

你应该可以做类似这样的事情来使用DbContext类型实例化中的HTTP请求内容:

using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    services.AddScoped<HttpContext>(p => p.GetService<IHttpContextAccessor>()?.HttpContext);
    services.AddDbContext<MyDbContext>();

    var descriptor = new ServiceDescriptor(
        typeof(DbContextOptions<MyDbContext>),
        DbContextOptionsFactory,
        ServiceLifetime.Scoped);

    var descriptorNonGeneric = new ServiceDescriptor(
        typeof(DbContextOptions),
        typeof(DbContextOptions<MyDbContext>), 
        ServiceLifetime.Scoped);

    services.Replace(descriptor);
    services.Replace(descriptorNonGeneric);

    // ...
}

private DbContextOptions<MyDbContext> DbContextOptionsFactory(IServiceProvider provider)
{
    var httpContext = provider.GetService<HttpContext>();
    // here we have the complete HttpContext
    var myHeader = httpContext.Request.Headers["MyHeader"];
    var connectionString = GetConnectionStringFromHeader(myHeader);

    var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
    optionsBuilder.UseSqlServer(connectionString);

    return optionsBuilder.Options;
}
Run Code Online (Sandbox Code Playgroud)

因为AddDbContext<TDbContext>EFCore 的扩展方法已经注册DbContextOptions为单例,我们需要覆盖这个注册并添加我们自己的DbContextOption工厂方法,该方法使用HttpContext和执行Scoped生命周期.

这样我们可以在每个请求上更改选项(包括连接字符串).


Mar*_*tin 6

这样你可以做的更精简

services.AddScoped<ISqlConnectionContext, SqlConnectionContext>();
services.AddDbContext<SqlDbContext>((sp, builder) =>
    builder.UseSqlServer(sp.GetRequiredService<ISqlConnectionContext>().GetConnectionString()));
Run Code Online (Sandbox Code Playgroud)

SqlConnectionContext现在可以在任何你想要的方式来实现。例如使用IHttpContextAccessor.

  • 看起来像 services.Replace from Accepted Answer 在 .net core 3.1 中不再存在,这对我有用。 (2认同)