【问题标题】:Injecting app settings via DI based on generic type in .NET Core 3.1基于 .NET Core 3.1 中的泛型类型通过 DI 注入应用程序设置
【发布时间】:2020-04-18 17:18:20
【问题描述】:

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

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

例如,类型 Player 的 MongoDB 集合名称被命名为 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


    【解决方案1】:

    您与typeof(T) 走在了正确的轨道上。您缺少的唯一步骤是您可以在GameDatabaseSettings 中使用bind a list of key/value pairs in your appSettings.json to a Dictionary&lt;string, string&gt;

    这将允许您根据字符串名称查找配置值,从而允许您通过 appSettings.json 配置任何通用 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)}."
        )
    );
    

    【讨论】:

    • 这很聪明,我不知道你可以映射字典
    • @Bugbeeb:是的!配置系统非常灵活。这里唯一真正的限制是键当前必须是字符串——这显然可以满足您的需求。也就是说,如果您需要为数据引入额外的维度(例如,每种类型的多个元数据,而不仅仅是集合名称),您甚至可以使用复杂的对象作为您的值。祝你的项目好运。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    • 1970-01-01
    • 1970-01-01
    • 2018-07-28
    • 2021-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多