После этого поста: https://blog.bredvid.no/validating-configuration-in-asp-net-core-e9825bd15f10
Теперь я могу проверить настройки, когда сервису это нужно. То, что я хотел бы сделать, это проверить непосредственно при запуске сервера в program.cs.
Я не уверен, как это сделать? Есть ли способ получить список служб, введенных в DI, затем проверить, можно ли назначить тип из IOption, и зарегистрировать его?
Вот как я могу добавить в DI Настройки:
//App settings
services.ConfigureAndValidate<AuthenticationSettings>(Configuration);
services.ConfigureAndValidate<SmtpSettings>(Configuration);
Код расширения:
public static class IServiceCollectionExtensions
{
public static IServiceCollection ConfigureAndValidate<T>(
this IServiceCollection serviceCollection,
IConfiguration config,
string section = null
) where T : class
{
var configType = typeof(T).Name;
if (string.IsNullOrEmpty(section)) {
section = configType;
}
return serviceCollection
.Configure<T>(config.GetSection(section))
.PostConfigure<T>(settings =>
{
var configErrors = settings.ValidationErrors().ToArray();
if (configErrors.Any())
{
var aggrErrors = string.Join(",", configErrors);
var count = configErrors.Length;
throw new ApplicationException($"Found {count} configuration error(s) in {configType}: {aggrErrors}");
}
});
}
private static IEnumerable<string> ValidationErrors(this object obj)
{
var context = new ValidationContext(obj, serviceProvider: null, items: null);
var results = new List<ValidationResult>();
Validator.TryValidateObject(obj, context, results, true);
foreach (var validationResult in results)
{
yield return validationResult.ErrorMessage;
}
}
}
Вот мой текущий лаунчер:
public class Program
{
public static async Task Main(string[] args)
{
var webHost = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddEnvironmentVariables();
var env = hostingContext.HostingEnvironment;
config.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
})
.UseStartup<Startup>()
.Build();
using (var scope = webHost.Services.CreateScope())
{
var services = scope.ServiceProvider;
/// <---- BEGIN / AN IDEA OF WHAT I WOULD LIKE TO DO ---->
/// <---- THIS CODE IS NOT WORKING ---->
var allServices = services.GetAllServices();
if (allServices != null)
{
foreach (var service in allServices )
{
if (service.ServiceType.IsAssignableFrom(IOptions))
{
services.GetRequiredService<service.ServiceType>()
}
}
}
/// <---- END ---->
}
await webHost.RunAsync();
}
}
Дайте мне знать, если у вас есть какие-либо предложения в комментарии.
Спасибо за вашу помощь.
РЕДАКТИРОВАТЬ 1:
Спасибо Стивену за вашу помощь, с вашим ответом, он помог мне продолжить находить ответ, но вещи все еще отсутствуют.
теперь все мои настройки наследуются от ISettings, например:
public class AuthenticationSettings : ISettings
{
[Required]
public string Issuer { get; set; }
[Required]
public string Audience { get; set; }
[Required]
public string SecretKey { get; set; }
[Required]
public int ExpirationDurationInDays { get; set; }
}
Я обновляю 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();
так что теперь мне нужно создать экземпляр каждой опции в опциях и получить значение. Я все еще работаю над этим. дайте мне знать, если у вас есть предложение или решение:)