如何将 appsetting.json 部分加载到 .NET Core 中的 Dictionary 中?

Posted

技术标签:

【中文标题】如何将 appsetting.json 部分加载到 .NET Core 中的 Dictionary 中?【英文标题】:How to load appsetting.json section into Dictionary in .NET Core? 【发布时间】:2017-08-08 08:21:57 【问题描述】:

我熟悉将 appsettings.json 部分加载到 .NET Core startup.cs 中的强类型对象中。例如:

public class CustomSection 

   public int A get;set;
   public int B get;set;


//In Startup.cs
services.Configure<CustomSection>(Configuration.GetSection("CustomSection"));

//Inject an IOptions instance
public HomeController(IOptions<CustomSection> options) 

    var settings = options.Value;

我有一个 appsettings.json 部分,其键/值对的数量和名称会随着时间的推移而变化。因此,在类中硬编码属性名称是不切实际的,因为新的键/值对需要在类中更改代码。一些键/值对的小样本:

"MobileConfigInfo": 
    "appointment-confirmed": "We've booked your appointment. See you soon!",
    "appointments-book": "New Appointment",
    "appointments-null": "We could not locate any upcoming appointments for you.",
    "availability-null": "Sorry, there are no available times on this date. Please try another."

有没有办法将此数据加载到 MobileConfigInfo 字典对象中,然后使用 IOptions 模式将 MobileConfigInfo 注入控制器?

【问题讨论】:

嗯,这个问题真的不是关于 ASP.NET Core 而不是 .NET Core 吗?有点误导的标题。 【参考方案1】:

采用这种结构格式:

"MobileConfigInfo": 
    "Values": 
       "appointment-confirmed": "We've booked your appointment. See you soon!",
       "appointments-book": "New Appointment",
       "appointments-null": "We could not locate any upcoming appointments for you.",
       "availability-null": "Sorry, there are no available times on this date. Please try another."
 

让你的设置类看起来像这样:

public class CustomSection 

   public Dictionary<string, string> Values get;set;

然后这样做

services.Configure<CustomSection>((settings) =>

     Configuration.GetSection("MobileConfigInfo").Bind(settings);
);

【讨论】:

这对我有用。如果字典更深入部分配置,也可以使用绑定调用。 加上这个,只要你使用services.AddOptions() from Microsoft.Extensions.Options,你就不需要使用Bind。这就够了:services.Configure&lt;CustomSection&gt;(Configuration.GetSection("MobileConfigInfo"));【参考方案2】:

对于想要将其转换为字典的其他人,

appsettings.json 中的示例部分

"MailSettings": 
    "Server": "http://mail.mydomain.com"        
    "Port": "25",
    "From": "info@mydomain.com"
 

下面的代码应该放在 Startup 文件中 > ConfigureServices 方法:

public static Dictionary<string, object> MailSettings  get; private set; 

public void ConfigureServices(IServiceCollection services)

    //ConfigureServices code......

    MailSettings = Configuration.GetSection("MailSettings").GetChildren()
                  .ToDictionary(x => x.Key, x => x.Value);

现在您可以从任何地方访问字典,例如:

string mailServer = Startup.MailSettings["Server"];

一个缺点是所有值都将作为字符串检索,如果您尝试任何其他类型,则该值将为空。

【讨论】:

您不需要.Select(item =&gt; new KeyValuePair&lt;string, string&gt;(item.Key, item.Value)) 部分。你可以打电话给GetChildren().ToDictionary(x =&gt; x.Key, x =&gt; x.Value) 这应该是公认的答案,这是迄今为止最简单、最优雅的解决方案。 如果您需要非接口的Dictionary&lt;string,string&gt;,那么您可以致电new Dictionary&lt;string, string&gt;(Configuration.GetSection("mysettings").AsEnumerable())【参考方案3】:

你可以在startup.cs类中使用Configuration.Bind(settings);

你的设置类会像

public class AppSettings

    public Dictionary<string, string> MobileConfigInfo
    
        get;
        set;
    

希望对你有帮助!

【讨论】:

我试图理解您提供的示例,但它非常令人困惑。 settings 是什么? @Catalin settingsAppSettings 类的一个实例。 Bind 方法会将config.json 中的值映射到settings 实例。之后,您可以使用.AddSingleton 或类似的东西将其注入其他类 这不适用于具有Dictionary&lt;string, string&gt; 属性的类。 Bind 方法在运行时失败:System.InvalidOperationException: 'Cannot create instance of type 'System.String' because it is missing a public parameterless constructor.'【参考方案4】:

相信你可以使用下面的代码:

var config =  Configuration.GetSection("MobileConfigInfo").Get<Dictionary<string, string>>(); 

【讨论】:

为我工作。谢谢!【参考方案5】:

到目前为止,最简单的方法是定义您的配置类以从您想要支持的 Dictionary 类型继承。

public class MobileConfigInfo:Dictionary<string, string>

那么您的启动和依赖注入支持将与任何其他配置类型完全相同。

【讨论】:

目前为止最简单的。现在,如果有一种简单的方法可以使用整数作为键...... 这确实是一个 JSON 限制,因为它只允许字符串键。 我认为这应该是公认的答案。一些有助于合并的东西可能是急切的选项验证。就我而言,我想要一个枚举字典,但不想强制在配置中定义每个枚举值。这是一种进行急切验证的方法:github.com/aspnet/Extensions/issues/459#issuecomment-536547483 你是男人中的神【参考方案6】:

在 .NET Core 3.1 中,您可以执行以下操作...

appsettings.json:


  "myConfig": 
    "foo": "bar",
    "myMappings": 
      "key1": "value1",
      "key2": "value2"
    
  

配置模型

MyConfig.cs

public class MyConfig

    public string Foo  get; set; 
    public Dictionary<string, string> MyMappings  get; set; 

Startup.cs:

public void ConfigureServices(IServiceCollection services)

    services.Configure<MyConfig>(configuration.GetSection("myConfig"));

使用选项分类:

public class OptionsUsingClass

    public OptionsUsingClass(IOptions<MyConfig> myConfigOptions)
    
        // Be wary of nulls in real code.
        var myConfig = myConfigOptions.Value;

        // Examples with the above data.
        myConfig.Foo.Should().Be("bar");

        myConfig.MyMappings["key1"].Should().Be("value1");
        myConfig.MyMappings["key2"].Should().Be("value2");
    

这就是我使用 appsettings.json 字典映射的方式。

【讨论】:

【参考方案7】:

对于简单(可能是微服务)应用程序,您可以将其添加为单例 Dictionary&lt;string, string&gt;,然后将其注入您需要的任何位置:

var mobileConfig = Configuration.GetSection("MobileConfigInfo")
                    .GetChildren().ToDictionary(x => x.Key, x => x.Value);

services.AddSingleton(mobileConfig);

及用法:

public class MyDependantClass

    private readonly Dictionary<string, string> _mobileConfig;

    public MyDependantClass(Dictionary<string, string> mobileConfig)
    
        _mobileConfig = mobileConfig;
    

    // Use your mobile config here

【讨论】:

【参考方案8】:

我使用下面的方式:

appsettings.json:

  "services": 
      "user-service": "http://user-service:5000/",
      "app-service": "http://app-service:5000/"
   

startup.cs:

  services.Configure<Dictionary<string, string>>(Configuration.GetSection("services"));

用法:

private readonly Dictionary<string, string> _services;
public YourConstructor(IOptions<Dictionary<string, string>> servicesAccessor)

    _services = servicesAccessor.Value;

【讨论】:

不确定为什么这不是最佳答案,因为几乎所有其他答案都错过了 OP 希望通过 IOptions 和依赖注入来消耗它们的事实。无论如何,这对我很有帮助,谢谢。【参考方案9】:

唯一对我有用的东西(ASP.NET Core 3.0)是将以下内容添加到Startup.csConfigureServices 方法中:

services.Configure<Dictionary<string, string>>(dict => Configuration
    .GetSection("MySectionName")
    .GetChildren()
    .ToList()
    .ForEach(c => dict[c.Key] = c.Value));

【讨论】:

【参考方案10】:

作为 ASP.Net Core 2.1 中更复杂绑定的示例;根据the documention,我发现使用ConfigurationBuilder.Get&lt;T&gt;() 方法更容易使用。

ASP.NET Core 1.1 及更高版本可以使用 Get,它适用于整个部分。 Get 比使用 Bind 更方便。

我在Startup 方法中绑定了配置。

private Config Config  get; 

public Startup(IConfiguration Configuration)

    Config = Configuration.Get<Config>();

这将绑定appsettings 文件:


    "ConnectionStrings": 
        "Accounts": "Server=localhost;Database=Accounts;Trusted_Connection=True;",
        "test": "Server=localhost;Database=test;Trusted_Connection=True;",
        "Client": "Server=localhost;Database=DYNAMICALLY_BOUND_CONTEXT;Trusted_Connection=True;",
        "Support": "Server=localhost;Database=Support;Trusted_Connection=True;"
    ,
    "Logging": 
        "IncludeScopes": false,
        "LogLevel": 
            "Default": "Debug",
            "System": "Information",
            "Microsoft": "Information"
        
    ,
    "Plugins": 
        "SMS": 
            "RouteMobile": 
                "Scheme": "https",
                "Host": "remote.host",
                "Port": 84567,
                "Path": "/bulksms",
                "Username": "username",
                "Password": "password",
                "Source": "CompanyName",
                "DeliveryReporting": true,
                "MessageType": "Unicode"
            
        ,
        "SMTP": 
            "GenericSmtp": 
                "Scheme": "https",
                "Host": "mail.host",
                "Port": 25,
                "EnableSsl": true,
                "Username": "smtpuser@mail.host",
                "Password": "password",
                "DefaultSender": "noreply@companyname.co.uk"
            
        
    

进入这个配置结构:

[DataContract]
public class Config

    [DataMember]
    public Dictionary<string, string> ConnectionStrings  get; set; 
    [DataMember]
    public PluginCollection Plugins  get; set; 


[DataContract]
public class PluginCollection

    [DataMember]
    public Dictionary<string, SmsConfiguration> Sms  get; set; 
    [DataMember]
    public Dictionary<string, EmailConfiguration> Smtp  get; set; 


[DataContract]
public class SmsConfiguration

    [DataMember]
    public string Scheme  get; set; 
    [DataMember]
    public string Host  get; set; 
    [DataMember]
    public int Port  get; set; 
    [DataMember]
    public string Path  get; set; 
    [DataMember]
    public string Username  get; set; 
    [DataMember]
    public string Password  get; set; 
    [DataMember]
    public string Source  get; set; 
    [DataMember]
    public bool DeliveryReporting  get; set; 
    [DataMember]
    public string Encoding  get; set; 


[DataContract]
public class EmailConfiguration

    [DataMember]
    public string Scheme  get; set; 
    [DataMember]
    public string Host  get; set; 
    [DataMember]
    public int Port  get; set; 
    [DataMember]
    public string Path  get; set; 
    [DataMember]
    public string Username  get; set; 
    [DataMember]
    public string Password  get; set; 
    [DataMember]
    public string DefaultSender  get; set; 
    [DataMember]
    public bool EnableSsl  get; set; 

【讨论】:

这实际上是最好的解决方案。请注意,可以指定一个部分,例如GetSection("Plugins") 但此部分本身不能成为绑定的一部分。尽管即使没有这样的指定 Get&lt;T&gt; 将只绑定现有模型并忽略 json 的所有其他部分。完美的!此外,由于 Net Core 3.5 类属性是可选的。【参考方案11】:

您可以随时进行:

appsettings.json:

   "MobileConfigInfo": 
      "a": "x",
      "b": "y",
      "c": "z"
    

代码中的某处:(不要忘记将 IConfiguration 依赖添加到类构造函数中)

var yourDictionary = _configuration.GetSection("MobileConfigInfo")
                .Get<IDictionary<string, string>>();

【讨论】:

【参考方案12】:

我有一个用于设置字典类型属性的通用解决方案,例如从选项中检索的 html 属性字典。

默认字典值可以在options中设置。如果段中存在相同的键,则覆盖字典中的值,否则插入键值对。

字典为IDictionary&lt;string, object&gt;类型,读取的值不解析,设置为字符串类型。

using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Extensions.DependencyInjection

    public static class JJurOptionsExtensions
    
        /// <summary>
        /// Binding configuration of the property of type IDictionary string, object
        /// </summary>
        /// <typeparam name="TOptions">
        /// The type of class that contains the property to be set
        /// </typeparam>
        /// <param name="services">
        /// IoC container
        /// </param>
        /// <param name="section">
        /// Section containing key-value pairs for the dictionary to be set
        /// </param>
        /// <returns>
        /// IServiceCollection
        /// </returns>
        /// <param name="property">
        /// Delegate of the property to be set
        /// </param>
        public static IServiceCollection ConfigureDictionary<TOptions>(
            this IServiceCollection services,
            IConfigurationSection section,
            Func<TOptions, IDictionary<string, object>> property)
                where TOptions : class
        
            var values = section        // List of sub-sections
                .GetChildren()
                .ToList();

            services.Configure<TOptions>(options =>
            
                var dict = property(options);
                values.ForEach(v =>
                
                    // If there is not key, then insert it.
                    // If there is, override the value.

                    dict[v.Key] = v.Value;
                );
            );

            return services;
        
    

使用示例:

        services.Configure<JJurCoreLibs.HtmlSortMnu.SortMenuOptions>(
                options => configuration.GetSection("SortMenuOptions").Bind(options)
            )
            .ConfigureDictionary<JJurCoreLibs.HtmlSortMnu.SortMenuOptions>(
                configuration.GetSection("SortMenuOptions:DropDownBbtnHtmlAttributes"),
                o => o.DropDownBbtnHtmlAttributes);

SortMenuOptions 类包含一个名为 DropDownBtnHtmlAttribute 的属性,类型为 Dictionary&lt;string, object&gt;

using System.Collections.Generic;

namespace JJurCoreLibs.HtmlSortMnu

    /// <summary>
    /// Options of the Bootstrap dropdown creating service for sorting items
    /// </summary>
    public class SortMenuOptions
    
...
        public DropDownBbtnHtmlAttributes DropDownBbtnHtmlAttributes  get;  = new DropDownBbtnHtmlAttributes 
             "role", "button" ,
             "data-toggle", "dropdown" ,
             "aria-expanded", false ,
             "aria-haspopup", true 
        ;
    

    public class DropDownBbtnHtmlAttributes : Dictionary<string, object>  


【讨论】:

以上是关于如何将 appsetting.json 部分加载到 .NET Core 中的 Dictionary 中?的主要内容,如果未能解决你的问题,请参考以下文章

<defaultProxy> 的 appsetting.json 版本是啥?

Appsetting.json 读取控制器类中键的值,空白?

如何在appsetting文件中存储API列表和授权密钥[重复]

.net core读取配置文件appsetting.json

解决.net core读取appSetting.json文件中文字符乱码

在 dotnet 核心中,对 config.GetSection().Get <List<object>> 的调用不会将值加载到对象中