ASP.Net 核心 DI 公司上下文提供者?

ASP.Net Core DI company context provider?

我正在使用 ASP.NET Core 3 实现一个 webapi。

在后端,我们有许多完全相同的公司数据库schema/tables等等

我正在尝试实现一个公司数据库上下文提供程序,它可以让我在运行时解析正确的公司数据库上下文。

在我的 startup.cs 中,我有以下代码,应该可以让您了解我正在尝试做什么:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<CompanyDbContext>(opt => opt.UseSqlServer(Configuration.GetConnectionString("CompanyDbConnection")));

    services.AddScoped<ICompanyRepository, CompanyRepository>();

    services.AddDbContext<System.Func<CompanyType, ICompanyDbContext>>(dbContextOptionsBuilder => key =>
    {
        switch (key)
        {
            case CompanyType.HKG:
                return dbContextOptionsBuilder.UseSqlServer(Configuration.GetConnectionString("HkgCompanyDbConnection"));
            case CompanyType.SHG:
                return dbContextOptionsBuilder.UseSqlServer(Configuration.GetConnectionString("ShgCompanyDbConnection"));
            default:
                throw new KeyNotFoundException();
        }
    });

    //...

而不是只有 1 个连接的通用 CompanyContext 我想注入服务提供者之类的东西,但是对于 dbcontexts 到 CompanyRepository 构造函数中,然后让我解析不同的公司存储库函数中不同情况下的 dbcontexts(通过传递参数)。

想法是代码的最后一部分应该 return 基于提供的密钥的正确上下文。但显然最后一部分不起作用。如果不是很明显,存储库 class 将保存所有函数 return 从数据库中获取数据。

如何解决这个问题?

根据评论,这是你可以做的,通过检查请求中的公司 ID 或名称,我怀疑这是否是你最终需要的。

哦,是的我忘了,这段代码是在.net core 2.2上测试的,但应该有所不同。

    services.AddScoped<ICompanyType, CompanyType>();
    services.AddEntityFrameworkSqlServer();
    services.AddDbContext<CompanyDbContext>((serviceProvider, options) =>
        {
            var companyCode = serviceProvider.GetRequiredService<ICompanyType>().Get();
            string connectionString = string.Empty;
            switch (companyCode)
            {
                case CompanyType.HKG:
                    connectionString = Configuration.GetConnectionString("HkgCompanyDbConnection");
                    break;
                case CompanyType.SHG:
                    connectionString = Configuration.GetConnectionString("ShgCompanyDbConnection");
                    break;
                default:
                    throw new InvalidOperationException();
            }
            options
                .UseSqlServer(connectionString)
                .UseInternalServiceProvider(serviceProvider);
        });

还有一些虚拟公司类型实现:

public class CompanyType: ICompanyType
{
    public const string HKG = "HKG";
    public const string SHG = "SHG";
    public string Get()
    {
        Random rand = new Random((int) DateTime.UtcNow.Ticks & 0x0000FFFF);
        var flipCoin = rand.Next(0, 1);
        return flipCoin == 0 ? HKG : SHG;
    }
}

public interface ICompanyType
{
    // dummy code, to be replaced with what is needed
    string Get();
}

我最近做了一些非常相似(但不完全)的事情并遇到了 我认为这正是您所追求的。

基本步骤:

共享代表

public delegate IService ServiceResolver(CompanyType key);

添加要解决的实例

//Note: Default Service Lifetime for AddDbContext is Scoped - perfect!
services.AddDbContext<HkgCompanyContext>(options...);
services.AddDbContext<ShgCompanyContext>(options...);

解析器服务

services.AddScoped<ServiceResolver>(serviceProvider => key =>
{
   switch (key)
   {
      case CompanyType.HKG:
         return serviceProvider.GetService(HkgCompanyContext);
      case CompanyType.SHG:
         return serviceProvider.GetService(ShgCompanyContext);
      default:
         throw new KeyNotFoundException();
   }
}