【问题标题】:Configure all options derived from base option class or interface .NET Core配置派生自基本选项类或接口 .NET Core 的所有选项
【发布时间】:2023-02-24 03:54:47
【问题描述】:

我在 appsettings.json 文件中有带有变量的代码,所以我通过配置方法在 IServiceCollection 中注册了所有选项:

public static void Configure(IServiceCollection services, IConfiguration configuration, bool useHangfire = true)
        {
            services
                .Configure<AuthSettings>(configuration.GetSection(AuthSettings.SectionName))
                .Configure<CacheSettings>(configuration.GetSection(CacheSettings.SectionName))
..... and so on

例如,我想创建一个基(抽象)类或接口

public interface ISettings
    {
        public const string SectionName = "DefaultSettings";
    }
public class AuthSettings: ISettings
    {
        public const string SectionName = "AuthSettings";

        public int ConfirmCodeLength { get; set; }
        public string AllowedChars { get; set; }
        public TimeSpan ConfirmCodeExpiry { get; set; }
}

并像这样配置所有设置

foreach (var type in
                Assembly.GetAssembly(typeof(ISettings)).GetTypes()
                    .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(ISettings))))
            {
                var currentSettings = (ISettings)Activator.CreateInstance(type);
                services.ConfigureOptions(currentSettings);
            }

我已经对 hangfire 作业的注册做了同样的事情,但这个案例看起来有点不同。 不幸的是,这个版本不起作用,因为 currentSetting 应该实现 IConfigureOptions 但它没有。另外我不确定这段代码是否从 JSON 中获取值。 有人做过这样的事吗?

【问题讨论】:

  • 是什么阻止你这样做?你面临什么实际问题?
  • 实际上这是行不通的。 services.ConfigureOptions 需要实现 IConfigureOptions<TOptions> 的参数,但它不需要。我不知道如何以正确的方式做到这一点
  • @Harish 谢谢!我只是通过反射解决这个问题

标签: c# asp.net dependency-injection


【解决方案1】:

所以,如果你有很多设置,你可以为所有设置创建基类,它有定义部分名称的方法

public class BaseSettings
{
    public virtual string SectionName => this.GetType().Name;
}

和许多这样的设置类

public class AuthSettings:BaseSettings
{
    public int ConfirmCodeLength { get; set; }
    public string AllowedChars { get; set; }
    public TimeSpan ConfirmCodeExpiry { get; set; }
}

然后在一个ServiceCollection扩展类的set方法中找到所有继承类并添加到IServiceCollection

public static IServiceCollection AddAllOptions(this IServiceCollection services, IConfiguration configuration)
    {
        foreach (var type in
            Assembly.GetAssembly(typeof(BaseSettings)).GetTypes()
                .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(BaseSettings))))
        {
            var configurationInstance = (BaseSettings)Activator.CreateInstance(type);
            if (configurationInstance != null)
            {
                var configurationSection = configuration.GetSection(configurationInstance.SectionName);
                var configureMethod = typeof(OptionsConfigurationServiceCollectionExtensions).GetMethods()
                    .Where(x => x.Name == "Configure")
                    .Single(m => m.GetParameters().Length == 2)
                    .MakeGenericMethod(type);
                configureMethod.Invoke(null, new object[] { services, configurationSection });
            }
        }

        return services;
    }

最后,您可以在 StartUp 类中使用此方法

service.AddAllOptions(configuration);

【讨论】:

    【解决方案2】:

    此处的答案帮助我解决了我的解决方案,但我发现了另一种方法,即使用 .NET 中的动态类型来创建类的实例并将动态实例传递给扩展方法以在运行时解析参数的类型。这使用实际的 Configure&lt;T&gt; 方法而不是反射来调用该方法。

    foreach (var type in Assembly.GetAssembly(typeof(ISettings)).GetTypes()
      .Where(myType => myType.IsClass && !myType.IsAbstract 
        && myType.GetInterfaces().Any(i => i == typeof(ISettings)))
    {
      var currentSettings = (ISettings)Activator.CreateInstance(type);
      var currentSettingsConfigurationSection = 
                        configuration.GetSection(currentSettings.Section);
      Configure(services, type, currentSettingsConfigurationSection );
    }
    
    private static IServiceCollection Configure(IServiceCollection services, Type type, IConfigurationSection section)
    {
        dynamic instance = Activator.CreateInstance(type);
        Configure(services, instance, section);
        return services;
    }
    
    private static IServiceCollection Configure<T>(IServiceCollection services, T _, IConfigurationSection section)
        where T : ISettings
    {
        services.Configure<T>(section);
        return services;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-12
      • 2010-09-08
      • 1970-01-01
      • 1970-01-01
      • 2019-09-05
      • 1970-01-01
      • 1970-01-01
      • 2015-01-12
      相关资源
      最近更新 更多