Внедрение нескольких строк подключения в конструктор c # - PullRequest
0 голосов
/ 04 апреля 2019

У меня есть сценарий использования, когда мне понадобится несколько строк подключения в моем слое доступа к данным, и я буду использовать любого, в зависимости от ввода.

В настоящее время у меня есть 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 Class:

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 голосов
/ 04 апреля 2019

Вы можете сохранить строки подключения в виде массива в вашем appsettings.json:

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

и сопоставить их с некоторым классом, используя шаблон параметров :

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”));
...