skip to Main Content

I have code with variables in appsettings.json file so I register all options in IServiceCollection via configure method:

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

I would like to create a base(abstract) class or interface for example

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; }
}

and configure all settings like this

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);
            }

I have alredy done the same with registration of hangfire jobs but this case looks a bit different.
Unfortunately this version doesn’t work bacause currentSetting should implenetn IConfigureOptions but it doesn’t. Also i’m not sure that this code get values from JSON.
Did someone do something like this?

2

Answers


  1. Chosen as BEST ANSWER

    So, if you has many settings you can create base class for all settings, that has method to define section name

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

    and many settings-classes like this

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

    Then in an ServiceCollection extention class set method to find all inherited classes and add it to 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;
        }
    

    Finally you can use this method in your StartUp class

    service.AddAllOptions(configuration);
    

  2. The answer here helped me get my solution working but I found another approach using the dynamic type in .NET to create an instance of your class and pass the dynamic instance to an extension method to resolve the type of the parameter at runtime. This uses the actual Configure<T> method instead of reflection to call the method.

    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;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search