I'm trying to be cheeky and create a base service for my MongoDB client. Inside my DI container I've injected database connection settings from the application.json
(as per Microsoft's MongoDB tutorial ).
What I can't figure out is the best way to access one of these setting properties based on a generic type passed into the constructor for the base service.
For example, the MongoDB collection name for Type Player
is named is Players . One idea I had was to do typeof(T)
instead of putting the key/value in the settings, but that cements the collection name to the type name.
Here is the database settings object being injected:
public class GameDatabaseSettings : IGameDatabaseSettings
{
public string PlayersCollectionName { get; set; }
public string ConnectionString { get; set; }
public string DatabaseName { get; set; }
public string LobbiesCollectionName { get; set; }
}
The application json:
"GameDatabaseSettings": {
"PlayersCollectionName": "Players",
"LobbiesCollectionName": "Lobbies",
"ConnectionString": "mongodb+srv://bugbeeb:*******@csharptest-yzm6y.mongodb.net/test?retryWrites=true&w=majority",
"DatabaseName": "DiceGameDB"
},
And here is how the base service operates:
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);
}
}
You were on the right track with typeof(T)
. The only step you were missing is that you can bind a list of key/value pairs in your appSettings.json
to a Dictionary<string, string>
in your GameDatabaseSettings
.
That will let you look up configuration values based on a string name, thus allowing you to configure the mappings between any generic Type
and an associated MongoDB collection name via your appSettings.json
.
So given the following appSettings.json
:
"GameDatabaseSettings": {
"CollectionNames": {
"Players": "Players",
"Lobbies": "Lobbies"
},
"ConnectionString": "mongodb+srv://bugbeeb:*******@csharptest-yzm6y.mongodb.net/test?retryWrites=true&w=majority",
"DatabaseName": "DiceGameDB"
}
}
You can bind to a settings object like:
public class GameDatabaseSettings : IGameDatabaseSettings
{
public Dictionary<string, string> CollectionNames { get; set; }
public string ConnectionString { get; set; }
public string DatabaseName { get; set; }
}
And now, within your service, you should be able to do something like:
_collection = db.GetCollection<T>(settings.CollectionNames[typeof(T).Name]);
Of course, you shouldn't assume that the correct mapping will be configured, so you'll likely want to write more defensive code, similar to:
_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)}."
)
);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.