简体   繁体   English

有没有办法修改 IOptionsSnapshot<t> 以编程方式而不是更改源文件?</t>

[英]Is there a way to modify an IOptionsSnapshot<T> programmatically instead of a change in the source file?

I have a transient class registered in ASP.NET Core's DI.我在 ASP.NET Core 的 DI 中注册了一个临时的 class。

An IOptions<T> is injected into its constructor. IOptions<T>被注入到它的构造函数中。 For every request and when needed, during runtime and based on a condition, I want to have another instance of IOptions injected.对于每个请求,在需要时,在运行时并根据条件,我想注入另一个IOptions实例。

Since IOptionsSnapshot<T> gets updated for every request when the source file gets updated, is there a way to mimic this behavior but instead of a change in the file, I want to programmatically make a change in IOptions , and before constructor injection, during runtime when a request comes in?由于IOptionsSnapshot<T>在源文件更新时针对每个请求进行更新,有没有办法模仿这种行为,而不是文件中的更改,我想以编程方式在IOptions中进行更改,并且在构造函数注入之前,在请求进来时的运行时间?

And use IOptionsSnapshot<T> instead of IOptions<T> for that.并为此使用IOptionsSnapshot<T>而不是IOptions<T>

Update:更新:

Condition example to be run before injection happens somewhere in the app like maybe a controller or action custom attribute?在注入发生在应用程序某处之前运行的条件示例,例如 controller 或操作自定义属性? In the attribute check a value and so:在属性中检查一个值等:

if (some condition) 
    Options.cnnectionstring = "string1"; 
else
    Options.cnnectionstring = "string2";

Injected into a class like this:像这样注入 class:

public class Books
{
    private readonly string connectionString;
    
    public Books(IOptions<DBOptions> options)
    {
        this.connectionString = options.Value.connectionString;
    }
    public void SomeMethod()
    {
        ....  //uses connectionString
    }
}       

Registered like this:像这样注册:

services.Configure<DBOptions>(options =>
{
    options.connectionString = "some connection string";
});     

    

IOption (like IConfiguration) is registered as singleton , but the request is scoped. IOption(如 IConfiguration)注册为 singleton ,但请求是有范围的。 Then it isn't possible to use request's information to modify the configuration.那么就无法使用请求的信息来修改配置。

You can use a intermediate scoped service, that retrieve the request's information and generate the desired connection string, like:您可以使用中间范围的服务,检索请求的信息并生成所需的连接字符串,例如:

public class BooksConnectionString
{
    public IConfiguration _configuration;
    public IHttpContextAccessor _httpContextAccessor;

    public BooksConnectionString(IConfiguration configuration, IHttpContextAccessor httpContextAccessor)
    {
        _configuration = configuration;
        _httpContextAccessor = httpContextAccessor;
    }

    public string ConnectionString
    {
        get
        {
            var library = _httpContextAccessor.HttpContext.Request.Query["library"].First();
            return _configuration.GetConnectionString(library);
        }
    }
}

Register the service as scoped:将服务注册为范围:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddHttpContextAccessor();
        services.AddScoped<BooksConnectionString>();
    }
    ...
}

Then you can inject like:然后你可以像这样注入:

public class Books
{
    private readonly string connectionString;

    public Books(BooksConnectionString options)
    {
        this.connectionString = BooksConnectionString.ConnectionString;
    }
} 

It's suppose you can modify the class where the connection string is injected.假设您可以修改注入连接字符串的 class。 If you can't modify this class, then you can register IOption as scoped:如果你不能修改这个class,那么你可以将IOption注册为作用域:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddHttpContextAccessor();
        services.AddScoped<IOptions<DBOptions>>(p =>
        {
            var configuration = p.GetService<IConfiguration>();
            var httpContextAccessor = p.GetService<IHttpContextAccessor>();
            var library = httpContextAccessor.HttpContext.Request.Query["library"].First();
            var dbOptions = configuration.GetSection("Databases").GetSection(library).Get<DBOptions>();
            return Options.Create(dbOptions);
        });
    }
    ...
}

Warning, IOption are expected as singleton. Register IOption as scoped would break this expectation.警告,IOption 应为 singleton。将 IOption 注册为作用域会破坏此预期。 To be used as a last resort.用作最后的手段。

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

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