首页 > 解决方案 > 基于 .NET Core 3.1 中的泛型类型通过 DI 注入应用程序设置

问题描述

我正在努力为我的 MongoDB 客户端创建一个基础服务。在我的 DI 容器中,我从application.json(根据Microsoft 的 MongoDB 教程)注入了数据库连接设置)注入了数据库连接设置。

我想不通的是基于传递给基本服务的构造函数的泛型类型来访问这些设置属性之一的最佳方法。

例如,Type 的 MongoDB 集合名称Player命名为Players。我的一个想法是不要typeof(T)将键/值放在设置中,而是将集合名称与类型名称结合起来。

这是注入的数据库设置对象:

    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);
        }

    }

标签: c#.net-core.net-core-3.1

解决方案


你在正确的轨道上typeof(T)。您缺少的唯一步骤是您可以将您的键/值对列表绑定appSettings.jsonDictionary<string, string>您的GameDatabaseSettings.

这将使您可以根据字符串名称查找配置值,从而允许您Type通过appSettings.json.

所以给出以下内容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)}."
    )
);

推荐阅读