我正在.Net Core 2.2中开发WebAPI。我需要一个自定义数据访问对象来查询数据。但是,我需要不同的连接才能完成不同的任务。使用DI和.NetCore IOptions模式实现此目的的最佳方法是什么?
我尝试在DAL对象中包含所有连接,并在调用该方法时指定连接ID。我可以为每个课程选择不同的课程,但是我想这太过分了。
让我们假设我将其放入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
。然后,在每个方法调用上,我需要指定所需的连接。
现在这是我的问题。如果我事先知道每个控制器类中需要哪个连接,该如何指定它,以便每个控制器使用我知道它将需要的连接?
更好的是,我可以在D容器中设置DAL类的几个不同实例,每个实例具有不同的连接,并让每个控制器类决定使用哪个实例吗?
感谢阅读。
答案 0 :(得分:1)
我建议使用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容器将确保只要已注册您的依赖项即可正确解析。