【问题标题】:Injecting multiple connection strings in constructor c#在构造函数c#中注入多个连接字符串
【发布时间】:2019-04-05 02:00:48
【问题描述】:

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

目前,我在 JSON 中添加了 2 个连接字符串,然后我将两者都注入。

是否有任何其他解决方案可以一次注入所有连接字符串,因为将来引入任何新数据库时,我必须在 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);
}

数据访问类:

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 类?

有什么帮助吗?

【问题讨论】:

  • 您的数据库类可以有一个带有IEnumerable&lt;string&gt; connectionStrings 参数的构造函数,并在内部处理每个查询应该针对哪个连接启动。
  • @bradbury9:这个数据库类不是我创建的,它来自 Microsoft.Practices.EnterpriseLibrary.Data 库。

标签: c# dependency-injection solid-principles


【解决方案1】:

您可以将连接字符串作为数组保存在您的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();

        // ...
    }

    // ...
}

更新:选项模式的代码 sn-ps:

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

【讨论】:

  • 你还没有在 StartUp 类中配置它,它会将 null 传递给构造函数中的选项值。
  • @Ritesh 我提到它需要使用选项模式进行配置。我不知道您的 appsettings.json 文件的确切结构,因此我无法提供为该部分截取的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-04-30
  • 1970-01-01
  • 2015-08-08
  • 1970-01-01
  • 2020-04-22
  • 2020-01-02
  • 1970-01-01
相关资源
最近更新 更多