简体   繁体   English

在多租户应用程序中使用数据库中的 IOptions 和加载选项

[英]Using IOptions and load options from database with multi tenant application

I move an application to .net core and trying to use IOptions pattern.我将应用程序移动到 .net 核心并尝试使用 IOptions 模式。

My application is multi tenant with single database.我的应用程序是具有单个数据库的多租户。 System has global default options and I keep them in database (same as my old application) and also each tenant has own options.系统具有全局默认选项,我将它们保存在数据库中(与我的旧应用程序相同),并且每个租户都有自己的选项。 If tenant has no option with a key in global, so I need to use global option.如果租户没有全局键的选项,那么我需要使用全局选项。

In configuration, I handle to getting global options from database.在配置中,我处理从数据库中获取全局选项。 It is easy with example in documentation . 文档中的示例很容易。

However, each tenant options not going well.然而,每个租户的选择并不顺利。 Although I actually know what I want, I don't know how to do it in.Net Core.虽然我实际上知道我想要什么,但我不知道如何在 .Net Core 中做到这一点。

I test in a console application.我在控制台应用程序中进行测试。

class Program {
    static void Main(string[] args) {
        var services = ConfigureServices();

        var serviceProvider = services.BuildServiceProvider();

        serviceProvider.GetService<App>().Run();
    }

public class App {
    private readonly IOptionsSnapshot<DemoOptions> _options;

    public App(IOptionsSnapshot<DemoOptions> options) {
        _options = options;
    }

    public void Run() {
        Console.WriteLine("Hello from App.cs");
        Console.WriteLine($"DemoOptions:Global:Enabled={_options.Value.Enabled}");
        Console.WriteLine($"DemoOptions:Global:AutoRetryDelay={_options.Value.AutoRetryDelay}");
        Console.WriteLine($"DemoOptions:Global:IdentityOptions:MaxUserNameLength={_options.Value.IdentityOptions.MaxUserNameLength}");
    }
}

    private static IServiceCollection ConfigureServices() {
        IServiceCollection services = new ServiceCollection();

        //Load global configuration from database and use them.
        var config = LoadConfiguration();
        services.AddSingleton(config);
        
        services.AddDbContext<EntityConfigurationContext>(options => options.UseInMemoryDatabase("InMemoryDb"));
        services.AddScoped<ITenantService, TenantService>();

        
        //I take this part from example link in below. But I am not successed.
        services.AddSingleton<IOptionsMonitorCache<DemoOptions>,TenantOptionsCache<DemoOptions>>();
        services.AddTransient<IOptionsFactory<DemoOptions>,TenantOptionsFactory<DemoOptions>>();
        services.AddScoped<IOptionsSnapshot<DemoOptions>,TenantOptions<DemoOptions>>();
        services.AddSingleton<IOptions<DemoOptions>,TenantOptions<DemoOptions>>();


        // required to run the application
        services.AddTransient<App>();

        return services;
    }

    public static IConfiguration LoadConfiguration() {
        var builder = new ConfigurationBuilder();
        builder.Sources.Clear();

        builder.AddEntityConfiguration(options => options.UseInMemoryDatabase("InMemoryDb"));

        IConfigurationRoot configurationRoot = builder.Build();
        DemoOptions options = new();
        configurationRoot.GetSection($"{nameof(DemoOptions)}:{DemoOptions.Global}").Bind(options);

        Console.WriteLine($"DemoOptions:Global:Enabled={options.Enabled}");
        Console.WriteLine($"DemoOptions:Global:AutoRetryDelay={options.AutoRetryDelay}");
        Console.WriteLine($"DemoOptions:Global:IdentityOptions:MaxUserNameLength={options.IdentityOptions.MaxUserNameLength}");

        return builder.Build();
    }
}

public record DemoOptions {
    public const string Global = nameof(Global);
    public const string Tenant = nameof(Tenant);

    public bool Enabled { get; set; }
    public TimeSpan AutoRetryDelay { get; set; }
    public IdentityOptions IdentityOptions { get; set; }
}

public record IdentityOptions {
    public int MaxUserNameLength { get; set; }
}

public record DemoSettings(string Key, string Value) {
    public int Id { get; set; }
}

public record TenantSettings(string Key, string Value, int TenantId) {
    public int Id { get; set; }
}

I add some important class here.我在这里添加了一些重要的 class。 However if you want to look at all project, I add github link .但是,如果您想查看所有项目,我添加github 链接 I use this example我用这个例子

I see.我懂了。 You ought to do these things你应该做这些事情

  1. install a nuget package安装 nuget package

Microsoft.Extensions.Options.ConfigurationExtensions Microsoft.Extensions.Options.ConfigurationExtensions

  1. In your Programs.cs in ConfigureServices replace this code在 ConfigureServices 中的 Programs.cs 中替换此代码
    var config = LoadConfiguration();
    services.Configure<DemoOptions>(config.GetSection($"{nameof(DemoOptions)}:{DemoOptions.Global}"));
    services.AddSingleton(config);

You can try ready-to-useJsonRepositoryConfiguration Nuget package.您可以尝试现成的JsonRepositoryConfiguration Nuget package。 It also has a auto-refresh feature and works pretty much like configuration form JSON config files, only it expects the JSON config from your repository which can in turn bring the data from any internal/external storage including making a database call, API call etc.它还具有自动刷新功能,其工作方式与 JSON 配置文件的配置形式非常相似,只是它需要来自您的存储库的 JSON 配置,这反过来可以从任何内部/外部存储中获取数据,包括进行数据库调用,ZDB974238708CA 等.

You can mix different configuration provides (like this one and JSON config files) and use them together should you like to.您可以混合使用不同的配置提供(例如这个和 JSON 配置文件)并根据需要一起使用它们。 Confession: I am the author.忏悔:我是作者。

The next step would be using Named Options .下一步将使用Named Options

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM