Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как извлечь список из appsettings.json в ядре .NET

Автор вопроса: devlifeОтветов: 6

У меня есть файл appsettings.json, который выглядит так:

{
    "someSetting": {
        "subSettings": [
            "one",
            "two",
            "three"
         ]
    }
}

Когда я создаю свой корень конфигурации и делаю что-то вроде config["someSetting:subSettings"], он возвращает null, а фактические доступные настройки выглядят примерно так:

config["someSettings:subSettings:0"]

Есть ли лучший способ получить содержимое someSettings:subSettings в виде списка?

  • Может быть, это работает .. weblog.west-wind.com/posts/2016/may/23/ Venky 26.08.2016
  • Может быть. Я использую консольное приложение, которое не является asp.net, но я посмотрю, смогу ли я получить коллекцию сервисов. devlife 26.08.2016
  • Да, это работает и в консольных приложениях. Ничего особенного в asp.net Victor Hurdugaci 26.08.2016
  • Я спрашиваю только потому, что получаю следующее: Could not load file or assembly 'Microsoft.Extensions.Configuration.Binder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. The system cannot find the file specified devlife 29.08.2016
  • Вы также можете использовать класс DTO для анализа конфигурации VMAtm 03.10.2017

Ответы

Ответ 1 · рейтинг 48 · Victor Hurdugaci

Вы можете использовать связыватель конфигурации, чтобы получить строгое представление источников конфигурации.

Это пример из теста, который я написал ранее, надеюсь, он поможет:

    [Fact]
    public void BindList()
    {
        var input = new Dictionary<string, string>
        {
            {"StringList:0", "val0"},
            {"StringList:1", "val1"},
            {"StringList:2", "val2"},
            {"StringList:x", "valx"}
        };

        var configurationBuilder = new ConfigurationBuilder();
        configurationBuilder.AddInMemoryCollection(input);
        var config = configurationBuilder.Build();

        var list = new List<string>();
        config.GetSection("StringList").Bind(list);

        Assert.Equal(4, list.Count);

        Assert.Equal("val0", list[0]);
        Assert.Equal("val1", list[1]);
        Assert.Equal("val2", list[2]);
        Assert.Equal("valx", list[3]);
    }

Важная часть - это звонок Bind.

Тест и другие примеры находятся на

Ответ 2 · рейтинг 169 · Kirill Rakhman

Предположим, ваш appsettings.json выглядит так:

{
  "foo": {
    "bar": [
      "1",
      "2",
      "3"
    ]
  }
}

Вы можете извлечь элементы списка следующим образом:

Configuration.GetSection("foo:bar").Get<List<string>>()

Ответ 3 · рейтинг 42 · Post Impatica

В .NetCore я сделал вот что:

Нормальная настройка

В вашем appsettings.json создайте раздел конфигурации для ваших пользовательских определений:

    "IDP": [
    {
      "Server": "asdfsd",
      "Authority": "asdfasd",
      "Audience": "asdfadf"
    },
    {
      "Server": "aaaaaa",
      "Authority": "aaaaaa",
      "Audience": "aaaa"
    }
  ]

Создайте класс для моделирования объектов:

public class IDP
{
    public String Server { get; set; }
    public String Authority { get; set; }
    public String Audience { get; set; }

}

в вашем автозагрузке - ›ConfigureServices

services.Configure<List<IDP>>(Configuration.GetSection("IDP"));

Примечание: если вам нужно немедленно получить доступ к вашему списку в методе ConfigureServices, вы можете использовать ...

var subSettings = Configuration.GetSection("IDP").Get<List<IDP>>();

Тогда в вашем контроллере что-то вроде этого:

Public class AccountController: Controller
{
    private readonly IOptions<List<IDP>> _IDPs;
    public AccountController(IOptions<List<Defined>> IDPs)
    {
        _IDPs = IDPs;
    }
  ...
}

просто в качестве примера я использовал его в другом месте в указанном выше контроллере следующим образом:

       _IDPs.Value.ForEach(x => {
            // do something with x
        });

Edge Case

В случае, если вам нужно несколько конфигураций, но они не могут быть в массиве, и вы не знаете, сколько подпараметров у вас будет одновременно. Используйте следующий метод.

appsettings.json

"IDP": {
    "0": {
      "Description": "idp01_test",
      "IDPServer": "https://intapi.somedomain.com/testing/idp01/v1.0",
      "IDPClient": "someapi",
      "Format": "IDP"
    },
    "1": {
      "Description": "idpb2c_test",
      "IDPServer": "https://intapi.somedomain.com/testing/idpb2c",
      "IDPClient": "api1",
      "Format": "IDP"
    },
    "2": {
      "Description": "MyApp",
      "Instance": "https://sts.windows.net/",
      "ClientId": "https://somedomain.com/12345678-5191-1111-bcdf-782d958de2b3",
      "Domain": "somedomain.com",
      "TenantId": "87654321-a10f-499f-9b5f-6de6ef439787",
      "Format": "AzureAD"
    }
  }

Модель

public class IDP
{
    public String Description { get; set; }
    public String IDPServer { get; set; }
    public String IDPClient { get; set; }
    public String Format { get; set; }
    public String Instance { get; set; }
    public String ClientId { get; set; }
    public String Domain { get; set; }
    public String TenantId { get; set; }
}

Создать расширение для объекта Expando

public static class ExpandObjectExtension
    {
        public static TObject ToObject<TObject>(this IDictionary<string, object> someSource, BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public)
               where TObject : class, new()
        {
            Contract.Requires(someSource != null);
            TObject targetObject = new TObject();
            Type targetObjectType = typeof(TObject);

            // Go through all bound target object type properties...
            foreach (PropertyInfo property in
                        targetObjectType.GetProperties(bindingFlags))
            {
                // ...and check that both the target type property name and its type matches
                // its counterpart in the ExpandoObject
                if (someSource.ContainsKey(property.Name)
                    && property.PropertyType == someSource[property.Name].GetType())
                {
                    property.SetValue(targetObject, someSource[property.Name]);
                }
            }

            return targetObject;
        }
    }

ConfigureServices

var subSettings = Configuration.GetSection("IDP").Get<List<ExpandoObject>>();

var idx = 0;
foreach (var pair in subSettings)
{

    IDP scheme = ((ExpandoObject)pair).ToObject<IDP>();
    if (scheme.Format == "AzureAD")
    {
        // this is why I couldn't use an array, AddProtecedWebApi requires a path to a config section
        var section = $"IDP:{idx.ToString()}";
        services.AddProtectedWebApi(Configuration, section, scheme.Description);
        // ... do more stuff

    }
    idx++;
}

Ответ 4 · рейтинг 7 · Marc S

var settingsSection = config.GetSection["someSettings:subSettings"];
var subSettings = new List<string>;

foreach (var section in settingsSection.GetChildren())
{
    subSettings.Add(section.Value);
}

Это должно дать вам необходимые значения, хранящиеся в subSettings

Приносим извинения за то, что подняли полустарую ветку. Мне было трудно найти ответ, так как многие методы устарели, например Get и GetValue. Это должно быть хорошо, если вам нужно только простое решение без привязки конфигурации. :)

Ответ 5 · рейтинг 3 · Michael Freidgeim

В моем случае конфигурация

 services.Configure<List<ApiKey>>(Configuration.GetSection("ApiKeysList"));

не был загружен, потому что свойства были доступны только для чтения и не было конструктора по умолчанию

// Не работает

  public class ApiKey : IApiKey
    {
        public ApiKey(string key, string owner)
        {
            Key = key;
            OwnerName = owner;
        }
        public string Key { get;  }
        public string OwnerName { get;}
    }

// Работаем

    public class ApiKey : IApiKey
    {
        public ApiKey(){}//Added default constructor
        public ApiKey(string key, string owner)
        {
            Key = key;
            OwnerName = owner;
        }
        public string Key { get; set; }        //Added set property
        public string OwnerName { get; set; }  //Added set property
    }

Ответ 6 · edelwater

Просто получение всего раздела заполнит свойство List; в классе настроек.

services.Configure<Settings>(configuration.GetSection("Another:Some:Example"));

Но ... помните, что если в классе настроек для этого списка установлены значения по умолчанию ... что настройки конфигурации будут добавочными и, следовательно, не будут перезаписывать исходные значения.

Таким образом, эти значения по умолчанию останутся, и вы не сможете удалить их с помощью каких-либо дополнительных настроек.

 public List<string> NonEditableStuff { get; set; } = new() { "XYZ1", "LTOY3" };

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

[Another:Some:Example:NonEditableStuff]
value=value
whatever2=whatever2

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы