在ASP.NET Core中注册Child IOptions

4
我有以下配置设置:
public void ConfigureServices(IServiceCollection services)
{
    var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
    services.Configure<AppSettings>(configuration);
}

public class AppSettings
{
    public ChildSettings Child { get; set; }

    public string Property { get; set; }
}

public class ChildSettings
{
    public string ChildProperty { get; set; }
}

我的appSettings.json文件如下所示:

{
    "Child": {
        "ChildProperty": "Value"
    }
    "Property": "Value"
}

我可以在控制器中轻松地注入 IOptions<AppSettings>

public class MyController : Controller
{
    public MyController(IOptions<AppSettings> options)
    {
        ChildSettings appSettings = options.Value;
    }
}

每次都要下到几个层级才能找到想要的设置对象,这已经有点陈旧了。我能否这样使用 IOptions<ChildSettings>

public class MyController : Controller
{
    public MyController(IOptions<ChildSettings> options)
    {
        ChildSettings appSettings = options.Value;
    }
}
3个回答

2
如果您想直接使用ChildSettings而不通过AppSettings对象,请按以下方式在DI配置中注册ChildSettings作为单独的条目: services.Configure<ChildSettings>(_configuration.GetSection("AppSettings:ChildSettings")); 但是,如果您想这样做,也许您可以将ChildSettings放在appsettings.json文件的根级别上?您不必在名为AppSettings的部分中拥有设置。

0

自动配置所有选项

PM> Install-Package Register.Options.Asp.Net.Core

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.ConfigureOptionsFromAssemblies(configuration, new List<Assembly>()
    {
        typeof(AppSettings).Assembly
    });

    ...
}

appsettings.json

{
    "ChildSettings": {
        "ChildProperty": "Value"
    }       
}

免责声明:package 的作者


0
可以通过实现自定义的IOptionsFactory<>来实现。
可复制代码:
用法:services.AddRecursiveOptions<AppSettings>(Configuration);
public static class RecursiveOptionsFactoryExtensions
{
    public static void AddRecursiveOptions<TAppSettings>(this IServiceCollection services, IConfiguration configuration)
        where TAppSettings : class
    {
        var appSettings = configuration.Get<TAppSettings>();
        services.AddSingleton<IAppSettingsProvider>(
            new AppSettingsProvider<TAppSettings>(appSettings!));
        services.AddTransient(typeof(IOptionsFactory<>), typeof(RecursiveResolvingOptionsFactory<>));
        services.Configure<TAppSettings>(configuration);
    }


    private interface IAppSettingsProvider
    {
        public object AppSettings { get; }
    }

    private class AppSettingsProvider<TAppSettings> : IAppSettingsProvider
    {
        public object AppSettings { get; }

        public AppSettingsProvider([DisallowNull] TAppSettings appSettings)
        {
            AppSettings = appSettings ?? throw new ArgumentNullException(nameof(appSettings));
        }
    }

    private class RecursiveResolvingOptionsFactory<TOptions> : IOptionsFactory<TOptions> where TOptions : class, new()
    {
        private readonly IEnumerable<IConfigureOptions<TOptions>> _setups;
        private readonly IEnumerable<IPostConfigureOptions<TOptions>> _postConfigures;
        private readonly IEnumerable<IValidateOptions<TOptions>>? _validations;
        private readonly object _appSettings;

        public RecursiveResolvingOptionsFactory(
            IEnumerable<IConfigureOptions<TOptions>> setups,
            IEnumerable<IPostConfigureOptions<TOptions>> postConfigures,
            IEnumerable<IValidateOptions<TOptions>>? validations,
            IAppSettingsProvider appSettings)
        {
            _setups = setups;
            _postConfigures = postConfigures;
            _validations = validations;
            _appSettings = appSettings.AppSettings;
        }

        private static TOptions? FindOptionsRecursively(object source)
        {
            var properties = source.GetType().GetProperties();
            foreach (var propertyInfo in properties)
            {
                var value = propertyInfo.GetValue(source);
                if (propertyInfo.PropertyType == typeof(TOptions))
                {
                    return (TOptions) value!;
                }

                if (!propertyInfo.PropertyType.IsClass || propertyInfo.PropertyType == typeof(string))
                {
                    continue;
                }

                var found = FindOptionsRecursively(value!);
                if (found != null)
                {
                    return found;
                }
            }

            return null;
        }

        public TOptions Create(string name)
        {
            // instead of creating default instance, like Microsoft.Extensions.Options.OptionsFactory<> does,
            // try finding if it is a property of AppSettings first
            var options = FindOptionsRecursively(_appSettings);
            if (options != null) return options;

            options = new TOptions();

            // copied from Microsoft.Extensions.Options.OptionsFactory<>
            foreach (IConfigureOptions<TOptions> setup in _setups)
            {
                if (setup is IConfigureNamedOptions<TOptions> configureNamedOptions)
                    configureNamedOptions.Configure(name, options);
                else if (name == Options.DefaultName)
                    setup.Configure(options);
            }

            foreach (IPostConfigureOptions<TOptions> postConfigure in _postConfigures)
                postConfigure.PostConfigure(name, options);
            if (_validations != null)
            {
                List<string> failureMessages = new List<string>();
                foreach (IValidateOptions<TOptions> validation in _validations)
                {
                    ValidateOptionsResult validateOptionsResult = validation.Validate(name, options);
                    if (validateOptionsResult.Failed)
                        failureMessages.AddRange(validateOptionsResult.Failures);
                }

                if (failureMessages.Count > 0)
                    throw new OptionsValidationException(name, typeof(TOptions), failureMessages);
            }

            return options;
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接