简体   繁体   中英

How to register two configurations that map to the same type in DI injector in ASP.NET Core

Let's say we have two connection strings - and that is just an example, I'm looking for a better way to implement this regardless of what I'm configuring - in the appSettings.json file:

  "ImportDb": {
    "StringConexao": "data source=server_n1;initial catalog=MyImportDb;user id=SYSDBA;password=masterkey;Charset=UTF8;",
    "BooleanProperty": false
  },
  "MainDb": {
    "StringConexao": "data source=server_n1;initial catalog=MyMainDb;user id=SYSDBA;password=masterkey;Charset=UTF8;",
    "BooleanProperty": false
  },

Today, I solve that mapping to 2 different types:

public class DbConfig
{
    public string StringConexao { get; set; }
    public bool BooleanProperty { get; set; }
}

public class LocalDbConfig: DbConfig
{

}

And registering in DI like this:

serviceCollection.Configure<DbConfig>(DadosConfig.GetSection("MainDb"));
serviceCollection.Configure<LocalDbConfig>(DadosConfig.GetSection("ImportDb"));

Why I solved that way:

  • Both configurations have exactly the same properties. They differ only on which class it's used.
  • The 2 configs can even refer to different servers, on two different networks in the case of string connections above.
  • I cannot treat them as an list (I need to be able address one or another on constructor)

It have some downsides:

  • Since the two types are descendants, if some requirements changes and a class that uses one of the configurations needs to accept the other as well I can't have two constructors each for each type of DbConfig - it confuses the DI injector.

So I ask: there's an more "elegant" way to do that kind of mapping?

Disclaimers:

  • user id=SYSDBA;password=masterkey is an login/password default to FirebirdSQL db server. It's well known for years.
  • "StringConexao" means "ConnectionString", for those curious.

I tried to create a someservicefactory to create services with different configrations as below:

public interface IDbconfig
    {
        public string StringConexao { get; set; }
        public bool BooleanProperty { get; set; }
    }
    public class DbConfig: IDbconfig
    {
        public string StringConexao { get; set; }
        public bool BooleanProperty { get; set; }
    }
    public interface IService
    {
         public string Test { get; set; }
         public string Test1 { get; set; }
    }
    public class Service: IService
    {
        public string Test { get; set; }
        public string Test1 { get; set; }
        public Service(List<DbConfig> config)
        {
            this.Test = config.First().StringConexao;
            this.Test1 = config.Last().StringConexao;
        }
    }
    public interface IServiceFactory
    {
        IServiceFactory Add(string key);
        IService Create(string key);
    }
    public class ServiceFactory : IServiceFactory
    {
       
        private readonly IConfiguration _configuration;
        private readonly Dictionary<string, IService> _someservices = new Dictionary<string, IService>();

        public ServiceFactory(IConfiguration configuration)
        {           
            _configuration = configuration;
            this.Add ("MainDb").Add("ImportDb").Add("MainDb,ImportDb");
        }

        public IServiceFactory Add(string key)
        {
            var keystringlist = key.Split(",").ToList();
            var configs = new List<DbConfig>();
            foreach(var newkey in keystringlist)
            {
                var config = new DbConfig();
                _configuration.GetSection(newkey).Bind(config);
                configs.Add(config);
            }
            var someservice = new Service(configs);
            _someservices.Add(key, someservice);
            return this;
        }
        public IService Create(string keyOfConfiguration)
        {
            return _someservices[keyOfConfiguration];
        }
    }

in startup.cs:

services.AddSingleton<IServiceFactory, ServiceFactory>();

inject the factory into controller or somewhere else and create services with different configs:

            var service1 = _serviceFactory.Create("ImportDb");
            var service2 = _serviceFactory.Create("MainDb");
            var service3 = _serviceFactory.Create("MainDb,ImportDb");

The result:

在此处输入图像描述 在此处输入图像描述

You say a list is not ok since you need to address the correct db in the constructor, but you could use a Dictionary. You can define a class DbConfigs:

public class DBConfigs
{
    public Dictionary<string, DBConfig> DBConfigurations { get; set; }
}

Then in the apSettings you can have:

"DBConfigs": {
    "DBConfigurations": {
        "ImportDb": {
            "StringConexao": "data source=server_n1;initial catalog=MyImportDb;user id=SYSDBA;password=masterkey;Charset=UTF8;",
            "BooleanProperty": false
         },
         "MainDb": {
             "StringConexao": "data source=server_n1;initial catalog=MyMainDb;user id=SYSDBA;password=masterkey;Charset=UTF8;",
             "BooleanProperty": false
         }
     }
 }

The registration in DI becomes:

serviceCollection.Configure<DbConfigs>(DadosConfig.GetSection("DBConfigs"));

And finally you can writhe your constructors in this way:

public MyClass(DBConfig aConfig)
{
    _myConfig = aConfig.DBConfigurations["MainDB"];
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM