如何从.net核心中的appsettings.json中提取列表


76

我有一个appsettings.json文件,看起来像这样:

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

当我构建配置根目录并执行类似的操作时,config["someSetting:subSettings"]它会返回null,而可用的实际设置如下所示:

config["someSettings:subSettings:0"]

有没有更好的方法来检索someSettings:subSettings列表内容?


可能是这样。.weblog.west
Venky

也许。我正在使用一个不是asp.net的控制台应用程序,但是我看看是否可以获取服务集合。
devlife

是的,它也适用于控制台应用程序。没什么特别的asp.net
Victor Hurdugaci,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

您还可以使用DTO类来解析配置
VMAtm '17

Answers:


41

您可以使用配置绑定程序来获得配置源的强类型表示。

这是我之前编写的测试中的一个示例,希望对您有所帮助:

    [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

测试和更多示例在GitHub上


自我说明:取决于Microsoft.Extensions.Configuration.Binder
Stefan Steiger

2
任何提示如何做到这一点services.Configure<TOptions>?欲注入从包括阵列的配置字段选项
亚当

152

假设您appsettings.json看起来像这样:

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

您可以像这样提取列表项:

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

7
这为我工作,但我必须首先安装“Microsoft.Extensions.Configuration.Binder” NuGet包,如所描述这里
Glorfindel

要获取键值对象对,您可以使用json2csharp创建C#类,然后使用Configuration.GetSection(“ foo”).Get <List <Bar >>()
马库斯

26

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

边缘盒

如果您需要多个配置,但是它们不能位于一个数组中,并且您不知道一次一次会有多少个子设置。使用以下方法。

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

配置服务

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

我创建了一个要绑定的类public class Definitions : List<Defined> {}。`{“定义”:[{“名称”:“ somename”,“标题”:“ sometitle”,“图像”:“某些图像URL”},{“名称”:“ somename”,“标题”:“ sometitle “,” Image“:”一些图片网址“}]}`
komaflash

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

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

这应该为您提供所需的值,存储在 subSettings

提出半旧线程的道歉。我已经很难找到答案了,因为不赞成使用大量的方法,例如GetGetValue。如果您只需要一个简单的解决方案而无需配置绑定程序,那应该很好。:)


1

就我而言

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

未加载,因为属性为只读且没有默认构造函数

 **//not working** 
  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
    } 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.