[英]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.