C# 如何从c Core中的DI获取可用的IOption列表?
在这篇文章之后: 我现在可以在服务需要时验证设置。我想做的是在program.cs中直接验证服务器何时启动 我不知道怎么做?是否有办法获取DI中注入的服务列表,然后验证该类型是否可从IOption分配并注册 以下是我如何向DI添加设置:C# 如何从c Core中的DI获取可用的IOption列表?,c#,dependency-injection,.net-core,C#,Dependency Injection,.net Core,在这篇文章之后: 我现在可以在服务需要时验证设置。我想做的是在program.cs中直接验证服务器何时启动 我不知道怎么做?是否有办法获取DI中注入的服务列表,然后验证该类型是否可从IOption分配并注册 以下是我如何向DI添加设置: //App settings services.ConfigureAndValidate<AuthenticationSettings>(Configuration); services.ConfigureAndValidat
//App settings
services.ConfigureAndValidate<AuthenticationSettings>(Configuration);
services.ConfigureAndValidate<SmtpSettings>(Configuration);
我更新Program.cs,比如:
using Autofac;
using Autofac.Core;
var options = services.GetService<ILifetimeScope>()
.ComponentRegistry
.Registrations.SelectMany(e => e.Services)
.Select(s => s as TypedService)
.Where(s => s.ServiceType.IsGenericType && s.ServiceType.GetGenericTypeDefinition() == typeof(IConfigureOptions<>))
.Select(s => s.ServiceType.GetGenericArguments()[0])
.Where(s => typeof(ISettings).IsAssignableFrom(s))
.ToList();
所以现在我需要实例化options中的每个选项并获得值。我还在努力。如果您有任何建议或解决方案,请告诉我:您可以通过迭代IServiceCollection实例获得已配置选项类型的列表:
var configuredOptionTypes =
from descriptor in services
let serviceType = descriptor.ServiceType
where serviceType.IsGenericType
where serviceType.GetGenericTypeDefinition() == typeof(IConfigureNamedOptions<>)
let optionType = serviceType.GetGenericArguments()[0]
select optionType;
根据Steven的建议,以下是我的解决方案: 我的设置验证程序服务
public SettingsValidator(
IServiceProvider services,
ILifetimeScope scope
)
{
var types = scope.ComponentRegistry.Registrations
.SelectMany(e => e.Services)
.Select(s => s as TypedService)
.Where(s => s.ServiceType.IsAssignableToGenericType(typeof(IConfigureOptions<>)))
.Select(s => s.ServiceType.GetGenericArguments()[0])
.Where(s => typeof(ISettings).IsAssignableFrom(s))
.ToList();
foreach (var t in types)
{
var option = services.GetService(typeof(IOptions<>).MakeGenericType(new Type[] { t }));
option.GetPropertyValue("Value");
}
}
扩展
public static class TypeExtensions
{
public static bool IsAssignableToGenericType(this Type givenType, Type genericType)
{
foreach (var it in givenType.GetInterfaces())
{
if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
return true;
}
if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return IsAssignableToGenericType(baseType, genericType);
}
}
在program.cs中
using (var scope = webHost.Services.CreateScope())
{
var services = scope.ServiceProvider;
var logger = services.GetRequiredService<ILogger<Program>>();
try
{
logger.LogInformation("Starting settings validation.");
services.GetRequiredService<SettingsValidator>();
logger.LogInformation("The settings have been validated.");
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred while validating the settings.");
}
}
让我知道它是否也适用于您:嗨,谢谢您的回答。在Program.cs中,我还没有IServiceCollection,我试图从services.GetRequiredService获取它,但它不起作用。我如何获得它?除非您显式地将IServiceCollection存储在某个位置,否则它将在使用该集合构建ServiceProvider后消失。但是你还不可能像以前那样拥有这个系列。这是您调用AddTransient和AddSingleton的对象。我找到了一种使用Autofac的方法,我将很快更新我的问题,但我仍然没有找到完整的答案,它已关闭:此集合在Startup类中可用。我更新了我的答案,现在我可以获得设置类型的列表。您知道如何执行以下操作吗:services.getServiceIOOptions
public SettingsValidator(
IServiceProvider services,
ILifetimeScope scope
)
{
var types = scope.ComponentRegistry.Registrations
.SelectMany(e => e.Services)
.Select(s => s as TypedService)
.Where(s => s.ServiceType.IsAssignableToGenericType(typeof(IConfigureOptions<>)))
.Select(s => s.ServiceType.GetGenericArguments()[0])
.Where(s => typeof(ISettings).IsAssignableFrom(s))
.ToList();
foreach (var t in types)
{
var option = services.GetService(typeof(IOptions<>).MakeGenericType(new Type[] { t }));
option.GetPropertyValue("Value");
}
}
builder.RegisterType<SettingsValidator>();
public class AzureStorageSettings : ISettings
{
[Required]
public string ConnectionString { get; set; }
[Required]
public string Container { get; set; }
[Required]
public string Path { get; set; }
}
public static class TypeExtensions
{
public static bool IsAssignableToGenericType(this Type givenType, Type genericType)
{
foreach (var it in givenType.GetInterfaces())
{
if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
return true;
}
if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
return true;
Type baseType = givenType.BaseType;
if (baseType == null) return false;
return IsAssignableToGenericType(baseType, genericType);
}
}
using (var scope = webHost.Services.CreateScope())
{
var services = scope.ServiceProvider;
var logger = services.GetRequiredService<ILogger<Program>>();
try
{
logger.LogInformation("Starting settings validation.");
services.GetRequiredService<SettingsValidator>();
logger.LogInformation("The settings have been validated.");
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred while validating the settings.");
}
}