在构造函数C#中注入多个连接字符串

时间:2019-04-04 14:16:56

标签: c# dependency-injection solid-principles

我有一个用例,在我的数据访问层中将需要多个连接字符串,并且将根据输入使用任何人。

目前,我有2个连接字符串,已在JSON中添加了这些字符串,然后将它们都注入了。

是否还有其他解决方案可一次注入所有连接字符串,因为将来随着引入任何新的数据库,我必须在JSON中再添加一个连接字符串,然后再次注入它?

启动类:

private static void Main(string[] args)
{
    ServiceCollection serviceCollection = new ServiceCollection();
    ConfigureServices(serviceCollection);

    IServiceProvider serviceProvider = 
    serviceCollection.BuildServiceProvider();
    serviceProvider.GetService<StudentApp>().Start();
}

private static void ConfigureServices(IServiceCollection 
serviceCollection)
{
    IConfigurationRoot configuration = GetConfiguration();
    Database database1 = new SqlDatabase(configuration.GetSection("Configuration:ConnectionString1").Value;
    Database database2 = new SqlDatabase(configuration.GetSection("Configuration:ConnectionString2").Value;

    // Here I am doing Multiple injections
    serviceCollection.AddSingleton(database1);
    serviceCollection.AddSingleton(database2);

    serviceCollection.AddOptions();
    serviceCollection.Configure<AppSettings(configuration.GetSection("Configuration"));
    serviceCollection.AddSingleton(configuration);

    serviceCollection.AddTransient<IStudentDataAccess,StudentDataAccess>();
    serviceCollection.AddTransient<StudentApp>();
}

private static IConfigurationRoot GetConfiguration()
{
    return new ConfigurationBuilder()
       .AddJsonFile("appsettings.json", optional: true)
       .Build();
}

StudentApp类:

private readonly IStudentDataAccess _dataAccess;
private readonly AppSettings _config;
private readonly Database _database1;
private readonly Database _database2;

public StudentApp(IStudentDataAccess dataAccess,IOptions<AppSettings> 
config, Database database1, Database database2)
{
     _dataAccess= dataAccess;
     _config = config.Value;
     _database1 = database1;
     _database2 = database2;
}

public void Start()
{
    int count= _dataAccess.GetStudentCount(deptId);
}

DataAccess类:

public interface IStudentDataAccess 
{
    int GetStudentCount(int deptId);
}

public class StudentDataAccess : IStudentDataAccess 
{
    private readonly AppSettings _config;
    private readonly Database _database1;
    private readonly Database _database2;
    public StudentDataAccess (IOptions<AppSettings> config, Database 
    database1,Database database2)
    {
         _config = config.Value;
         _database1 = database1;
         _database2 = database2;
    }

    public int GetStudentCount(int deptId)
    {
        // Execute queries either by Database1 or 2.
    }
 }

使用的数据库类来自Microsoft.Practices.EnterpriseLibrary.Data。 如何避免为不同的连接字符串创建多个Singleton类?

有帮助吗?

1 个答案:

答案 0 :(得分:0)

您可以将连接字符串作为数组保留在appsettings.json中:

{
  ...
  "ConnectionStrings": [
    {
      "Name": "ConnectionString1",
      "Value":  "some value"
    },
    {
      "Name": "ConnectionString1",
      "Value": "some value"
    }
  ]
}

并使用Options pattern将它们映射到某个类:

public class ConnectionStringOptions
{
    public ConnectionString[] ConnectionStrings { get; set; }
}
public class ConnectionString
{
    public string Name { get; set; }
    public string Value { get; set; }
}

然后,您可以拥有一个像这样的界面:

public interface IDatabaseProvider
{
    IEnumerable<Database> GetDatabases();
    Database GetDatabase(string name);
}

具有这样的实现

public class DatabaseProvider : IDatabaseProvider
{
    private readonly ConnectionStringOptions _options;

    public DatabaseProvider(IOptions<ConnectionStringOptions> optionsAccessor)
    {
        this._options = optionsAccessor.Value;
    }

    public IEnumerable<Database> GetDatabases()
    {
        foreach (ConnectionString connectionString in this._options.ConnectionStrings)
            yield return new SqlDatabase(connectionString.Value);
    }

    public Database GetDatabase(string name)
    {
        string connectionString = this._options.ConnectionStrings.SingleOrDefault(x => x.Name == name).Value;
        return new SqlDatabase(connectionString);
    }
}

现在,您只需注册IDatabaseProvider

serviceCollection.AddTransient<IDatabaseProvider, DatabaseProvider>()

,然后根据需要将其注入您的服务中。例如:

public class StudentApp
{
    private readonly IEnumerable<Database> _databases;

    public StudentApp(IStudentDataAccess dataAccess, IDatabaseProvider databasesProvider)
    {
        //Or get just the one you want by name
        this._databases = databasesProvider.GetDatabases();

        // ...
    }

    // ...
}

更新:“选项”模式的代码段:

serviceCollection.Configure<ConnectionStringOptions>(configuration.GetSection("ConnectionStrings”));