Внедрение настроек приложения через DI в зависимости от типа c. NET Core 3.1 - PullRequest
0 голосов
/ 18 апреля 2020

Я пытаюсь быть дерзким и создать базовый сервис для моего клиента MongoDB. Внутри моего DI-контейнера я вставил параметры подключения к базе данных из application.json (согласно руководства Microsoft по MongoDB ).

Что я не могу понять, так это лучший способ получить доступ к одному из этих свойств настроек на основе обобщенного типа c, переданного в конструктор для базовой службы.

Например, имя коллекции 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);
        }

    }

1 Ответ

1 голос
/ 18 апреля 2020

Вы были на правильном пути с typeof(T). Единственный пропущенный вами шаг - это то, что вы можете связать список пар ключ / значение в вашем appSettings.json с Dictionary<string, string> в вашем GameDatabaseSettings.

Это позволит вам искать значения конфигурации на основе имени строки, что позволяет вам настраивать сопоставления между любым generi c Type и соответствующим именем коллекции MongoDB через ваш 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)}."
    )
);
...