基于 .NET Core 3.1 中的通用类型通过 DI 注入应用程序设置
Injecting app settings via DI based on generic type in .NET Core 3.1
我想厚颜无耻地为我的 MongoDB 客户创建一个基础服务。在我的 DI 容器中,我从 application.json
(根据 Microsoft’s MongoDB tutorial)注入了数据库连接设置。
我想不通的是根据传递到基本服务的构造函数中的通用类型来访问这些设置属性之一的最佳方法。
例如,类型 Player
的 MongoDB 集合名称被命名为 Players。我的一个想法是做 typeof(T)
而不是将 key/value 放在设置中,但这将集合名称与类型名称结合在一起。
这是被注入的数据库设置对象:
public class GameDatabaseSettings : IGameDatabaseSettings
{
public string PlayersCollectionName { get; set; }
public string ConnectionString { get; set; }
public string DatabaseName { get; set; }
public string LobbiesCollectionName { get; set; }
}
申请json:
"GameDatabaseSettings": {
"PlayersCollectionName": "Players",
"LobbiesCollectionName": "Lobbies",
"ConnectionString": "mongodb+srv://bugbeeb:*******@csharptest-yzm6y.mongodb.net/test?retryWrites=true&w=majority",
"DatabaseName": "DiceGameDB"
},
基本服务的运作方式如下:
public interface IGameItem
{
public string Id { get; set; }
}
public class BaseService<T> where T:IGameItem
{
private readonly IMongoCollection<T> _collection;
public BaseService(IGameDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var db = client.GetDatabase(settings.DatabaseName);
_collection = db.GetCollection<T>(settings.CollectionName); //<-- How to make this T specific??
}
public virtual async Task<T> GetAsync(string id)
{
var result = await _collection.FindAsync(item => item.Id == id);
return result.FirstOrDefault();
}
public virtual async Task DeleteAsync(string id)
{
await _collection.FindOneAndDeleteAsync(item => item.Id == id);
}
}
您 typeof(T)
的方向是正确的。您唯一缺少的步骤是您可以 在您的 GameDatabaseSettings
.
这将使您可以根据字符串名称查找配置值,从而允许您通过 [=15= 配置任何通用 Type
和关联的 MongoDB 集合名称之间的映射].
所以给出以下 appSettings.json
:
"GameDatabaseSettings": {
"CollectionNames": {
"Players": "Players",
"Lobbies": "Lobbies"
},
"ConnectionString": "mongodb+srv://bugbeeb:*******@csharptest-yzm6y.mongodb.net/test?retryWrites=true&w=majority",
"DatabaseName": "DiceGameDB"
}
}
您可以绑定到设置对象,例如:
public class GameDatabaseSettings : IGameDatabaseSettings
{
public Dictionary<string, string> CollectionNames { get; set; }
public string ConnectionString { get; set; }
public string DatabaseName { get; set; }
}
现在,在您的服务中,您应该能够执行以下操作:
_collection = db.GetCollection<T>(settings.CollectionNames[typeof(T).Name]);
当然,您不应该假设会配置正确的映射,因此您可能希望编写更多防御性代码,类似于:
_collection = db.GetCollection<T>(
settings.CollectionNames.TryGetValue(
typeof(T).Name,
out var collectionName
)?
collectionName :
throw new ConfigurationError(
$"The ‘{typeof(T).Name}’ mapping is not configured as part of {nameof(GameDatabaseSettings)}."
)
);
我想厚颜无耻地为我的 MongoDB 客户创建一个基础服务。在我的 DI 容器中,我从 application.json
(根据 Microsoft’s MongoDB tutorial)注入了数据库连接设置。
我想不通的是根据传递到基本服务的构造函数中的通用类型来访问这些设置属性之一的最佳方法。
例如,类型 Player
的 MongoDB 集合名称被命名为 Players。我的一个想法是做 typeof(T)
而不是将 key/value 放在设置中,但这将集合名称与类型名称结合在一起。
这是被注入的数据库设置对象:
public class GameDatabaseSettings : IGameDatabaseSettings
{
public string PlayersCollectionName { get; set; }
public string ConnectionString { get; set; }
public string DatabaseName { get; set; }
public string LobbiesCollectionName { get; set; }
}
申请json:
"GameDatabaseSettings": {
"PlayersCollectionName": "Players",
"LobbiesCollectionName": "Lobbies",
"ConnectionString": "mongodb+srv://bugbeeb:*******@csharptest-yzm6y.mongodb.net/test?retryWrites=true&w=majority",
"DatabaseName": "DiceGameDB"
},
基本服务的运作方式如下:
public interface IGameItem
{
public string Id { get; set; }
}
public class BaseService<T> where T:IGameItem
{
private readonly IMongoCollection<T> _collection;
public BaseService(IGameDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var db = client.GetDatabase(settings.DatabaseName);
_collection = db.GetCollection<T>(settings.CollectionName); //<-- How to make this T specific??
}
public virtual async Task<T> GetAsync(string id)
{
var result = await _collection.FindAsync(item => item.Id == id);
return result.FirstOrDefault();
}
public virtual async Task DeleteAsync(string id)
{
await _collection.FindOneAndDeleteAsync(item => item.Id == id);
}
}
您 typeof(T)
的方向是正确的。您唯一缺少的步骤是您可以 GameDatabaseSettings
.
这将使您可以根据字符串名称查找配置值,从而允许您通过 [=15= 配置任何通用 Type
和关联的 MongoDB 集合名称之间的映射].
所以给出以下 appSettings.json
:
"GameDatabaseSettings": {
"CollectionNames": {
"Players": "Players",
"Lobbies": "Lobbies"
},
"ConnectionString": "mongodb+srv://bugbeeb:*******@csharptest-yzm6y.mongodb.net/test?retryWrites=true&w=majority",
"DatabaseName": "DiceGameDB"
}
}
您可以绑定到设置对象,例如:
public class GameDatabaseSettings : IGameDatabaseSettings
{
public Dictionary<string, string> CollectionNames { get; set; }
public string ConnectionString { get; set; }
public string DatabaseName { get; set; }
}
现在,在您的服务中,您应该能够执行以下操作:
_collection = db.GetCollection<T>(settings.CollectionNames[typeof(T).Name]);
当然,您不应该假设会配置正确的映射,因此您可能希望编写更多防御性代码,类似于:
_collection = db.GetCollection<T>(
settings.CollectionNames.TryGetValue(
typeof(T).Name,
out var collectionName
)?
collectionName :
throw new ConfigurationError(
$"The ‘{typeof(T).Name}’ mapping is not configured as part of {nameof(GameDatabaseSettings)}."
)
);