Как правильно реализовать диспетчер доступа к данным с поддержкой нескольких соединений, чтобы его можно было внедрить? - PullRequest
0 голосов
/ 28 января 2019

Я разрабатываю WebAPI в .Net Core 2.2.Мне нужен пользовательский объект доступа к данным для запроса данных.Однако мне нужны разные соединения для разных задач.Каков наилучший подход для этого с использованием шаблона ввода-вывода DI и .NetCore?

Я попытался установить все соединения в объекте DAL и указать идентификатор соединения при вызове метода.У меня есть возможность иметь разные классы для каждого, но я думаю, что это излишне.

Итак, давайте предположим, что у меня есть это в appsettings.json

"DatabaseMetaConfiguration": {
  "MappingDb": {
    "DNS": "pgc.app.corp.acme.com",
    "Database": "mappings",
    "User": "mappings_user",
    "Pass": "111",
    "SSL": "SSL Mode=Prefer; Trust Server Certificate=true"
  },
  "StatusDb": {
    "DNS": "pgc.app.corp.acme.com",
    "Database": "status",
    "User": "status_user",
    "Pass": "222",
    "SSL": "SSL Mode=Prefer; Trust Server Certificate=true"
  },
  "MasterDb": {
    "DNS": "pgc.app.corp.acme.com",
    "Database": "master",
    "User": "master_user",
    "Pass": "333",
    "SSL": "SSL Mode=Prefer; Trust Server Certificate=true"
  },
  "BookDb": {
    "DNS": "pgc.app-books.corp.acme.com",
    "Database": "book",
    "User": "book_user",
    "Pass": "444",
    "SSL": "SSL Mode=Prefer; Trust Server Certificate=true"
  }
}

Затем классы параметров POCO:

public class PostgreSqlDatabaseMetaConfigurations : Dictionary<string, PostgreSqlDatabaseMetaConfiguration> { }

public class PostgreSqlDatabaseMetaConfiguration
{
    public string Database { get; set; }
    public string User { get; set; }
    public string Pass { get; set; }
    public string DNS { get; set; }
    public string SSL { get; set; }
    public int Timeout { get; set; }
    public int CommandTimeout { get; set; }
    public string ConnectionString { get { [...] } }
}

И фактический класс DAL:

public class PostgreSqlManager : IDisposable, ISqlManager
{
    private readonly Dictionary<string, NpgsqlConnection> _connections;
    private readonly ILogger<PostgreSqlManager> _logger;

    public PostgreSqlManager(IOptionsMonitor<PostgreSqlDatabaseMetaConfigurations> optionsAccessor, ILogger<PostgreSqlManager> logger)
    {
        _logger = logger;
        var dbConfigurations = optionsAccessor.CurrentValue;
        if (dbConfigurations == null || !dbConfigurations.Any())
            _logger.LogWarning("No connections configured!");

        // Create a dictionary of connections, indexed by the connection names
        _connections = dbConfigurations.ToDictionary(c => c.Key, c => new NpgsqlConnection(c.Value.ConnectionString));
    }

    // So, a sample method would be...

    public async Task<long> ExecuteScalarAsync(string connectionId, string commandText, List<DbParameter> parameters = null, CommandType commandType = CommandType.Text)
    {
        using (var command = GetDbCommand(_connections[connectionId], commandText, parameters, commandType))
        {
            try
            {
                await command.Connection.OpenAsync();
                return (Int64)await command.ExecuteScalarAsync().ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Exception on ExecuteScalarAsync({0})", commandText);
                throw;
            }
            finally
            {
                command.CloseCommand();
            }
        }
    }
}

Наконец, в ConfigureServices у меня есть следующие строки:

services.AddSingleton<ISqlManager, PostgreSqlManager>();
services.Configure<PostgreSqlDatabaseMetaConfigurations>(configuration.GetSection("DatabaseMetaConfiguration"));

(извините за большие куски кода,Я хотел, чтобы это было ясно.)

Теперь, если я хочу использовать класс обслуживания DAL, мне нужно добавить ISqlManager в мой контроллер.Затем при каждом вызове метода мне нужно указать, какое соединение я хочу.

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

Еще лучше, могу ли я установить несколько разных экземпляров класса DALв DI-контейнер, каждый с различным соединением, и пусть каждый класс контроллера решает, какой из них использовать?

Спасибо за чтение.

1 Ответ

0 голосов
/ 29 января 2019

Я бы предложил использовать AddScoped для регистрации вашего PostgreSqlManager.Это сохранит работоспособность объекта на время веб-запроса.

Затем вы можете сделать что-то вроде

public interface IBookRepository
{
   Book GetByISBN(string isbn);
   Add(Book book)
   Delete(Book book)
}

public class BookRepository: IBookRepository
{
  private ISqlManager _sqlManager;

  public BookRepository(ISqlManager sqlManager)
  {
    _sqlManager = sqlManager;
  }

  public Book GetByISBN(string isbn)
  {
    var rows = _sqlManager.GetRows("BooksDb", "exec uspGetBookByISBN", CreateStringParam(isbn));

    // convert rows into book object(s)

   return books.FirstOrDefault();

  }

}

Теперь вы можете зарегистрировать один или несколько репозиториев на базу данных и зарегистрировать, например,

services.AddScoped ();

И в ваш контроллер вставьте те, которые вам нужны.

public class MyController: Controller
{
  private IBookRepository _bookRepository;
  private IStatusRepository _statusRepository;
  public MyController(IBookRepository bookRepository, IStatusRepository statusRepository)
  {
    _bookRepository = bookRepository; 
    _statusRepository = statusRepository
  }
}

Контейнер DI будет гарантировать правильное разрешение ваших зависимостей, покаони были зарегистрированы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...