简体   繁体   English

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

[英]How to load appsetting.json section into Dictionary in .NET Core?

I am familiar w/ loading an appsettings.json section into a strongly typed object in .NET Core startup.cs.我熟悉将 appsettings.json 部分加载到 .NET Core startup.cs 中的强类型对象中。 For example:例如:

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

I have an appsettings.json section who's key/value pairs will vary in number and name over time.我有一个 appsettings.json 部分,它的键/值对的数量和名称会随着时间的推移而变化。 Therefore, it's not practical to hard code property names in a class since new key/value pairs would require a code change in the class.因此,在类中对属性名称进行硬编码是不切实际的,因为新的键/值对需要在类中进行代码更改。 A small sample of some key/value pairs:一些键/值对的小样本:

"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."
}

Is there a way to load this data into a MobileConfigInfo Dictionary object and then use the IOptions pattern to inject MobileConfigInfo into a controller?有没有办法将此数据加载到 MobileConfigInfo 字典对象中,然后使用 IOptions 模式将 MobileConfigInfo 注入控制器?

Go with this structure format:使用这种结构格式:

"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."
 }
}

Make your setting class look like this:让你的设置类看起来像这样:

public class CustomSection 
{
   public Dictionary<string, string> Values {get;set;}
}

then do this然后这样做

services.Configure<CustomSection>((settings) =>
{
     Configuration.GetSection("MobileConfigInfo").Bind(settings);
});

For others who want to convert it to a Dictionary ,对于其他想要将其转换为Dictionary 的人

sample section inside appsettings.json appsettings.json 中的示例部分

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

Following code should be put inside the Startup file > ConfigureServices method:以下代码应放在启动文件 > 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);
}

Now you can access the dictionary from anywhere like:现在您可以从任何地方访问字典,例如:

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

One downside is that all values will be retrieved as strings, if you try any other type the value will be null.一个缺点是所有值都将作为字符串检索,如果您尝试任何其他类型,则该值将为空。

You can use Configuration.Bind(settings);您可以使用Configuration.Bind(settings); in startup.cs classstartup.cs类中

And your settings class will be like你的设置类会像

public class AppSettings
{
    public Dictionary<string, string> MobileConfigInfo
    {
        get;
        set;
    }
}

Hope it helps!希望能帮助到你!

我相信您可以使用以下代码:

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

By far the simplest method would be to define your configuration class to inherit from the Dictionary type you want to support.到目前为止,最简单的方法是定义您的配置类以从您想要支持的 Dictionary 类型继承。

public class MobileConfigInfo:Dictionary<string, string>{
}

Then your startup and dependency injection support would be exactly the same as for any other configuration type.那么您的启动和依赖注入支持将与任何其他配置类型完全相同。

For simple (perhaps microservice) applications you can just add it it as a singleton Dictionary<string, string> and then inject it wherever you need it:对于简单的(也许是微服务)应用程序,您可以将其添加为单例Dictionary<string, string> ,然后将其注入到您需要的任何位置:

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

services.AddSingleton(mobileConfig);

And the usage:以及用法:

public class MyDependantClass
{
    private readonly Dictionary<string, string> _mobileConfig;

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

    // Use your mobile config here
}

In .NET Core 3.1 you can do something like the following...在 .NET Core 3.1 中,您可以执行以下操作...

appsettings.json: appsettings.json:

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

A configuration model一个配置模型

MyConfig.cs配置文件

public class MyConfig
{
    public string Foo { get; set; }
    public Dictionary<string, string> MyMappings { get; set; }
}

Startup.cs:启动.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyConfig>(configuration.GetSection("myConfig"));

Class using the options:使用选项的类:

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

This was how I used appsettings.json dictionary mappings.这就是我使用 appsettings.json 字典映射的方式。

The only thing that worked for me (ASP.NET Core 3.0) was to add the following to the ConfigureServices method of Startup.cs :唯一对我有用(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));

I use the way below:我用下面的方法:

appsettings.json: appsettings.json:

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

startup.cs:启动.cs:

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

Usage:用法:

private readonly Dictionary<string, string> _services;
public YourConstructor(IOptions<Dictionary<string, string>> servicesAccessor)
{
    _services = servicesAccessor.Value;
}

As an example of more complex binding in ASP.Net Core 2.1;作为 ASP.Net Core 2.1 中更复杂绑定的示例; I found using the ConfigurationBuilder .Get<T>() method far easier to work with, as per the documention . 根据文档,我发现使用ConfigurationBuilder .Get<T>()方法更容易使用。

ASP.NET Core 1.1 and higher can use Get, which works with entire sections. ASP.NET Core 1.1 及更高版本可以使用 Get,它适用于整个部分。 Get can be more convenient than using Bind. Get 可以比使用 Bind 更方便。

I bound the configuration in my Startup method.我在Startup方法中绑定了配置。

private Config Config { get; }

public Startup(IConfiguration Configuration)
{
    Config = Configuration.Get<Config>();
}

This binds the appsettings file:这将绑定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"
            }
        }
    }
}

Into this configuration structure:进入这个配置结构:

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

You can do it on the fly:您可以即时完成:

appsettings.json:
{
   "MobileConfigInfo": {
      "a": "x",
      "b": "y",
      "c": "z"
    }
}

Somewhere in code: (don't forget to add IConfiguration dependency to the class constructor)代码中的某处:(不要忘记向类构造函数添加 IConfiguration 依赖项)

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

I have a generic solution for setting dictionary type properties, such as the dictionary of HTML attributes that are retrieved from options.我有一个用于设置字典类型属性的通用解决方案,例如从选项中检索的 HTML 属性字典。

Default dictionary values ​​can be set in options.可以在选项中设置默认字典值。 If the same key exists in the section, then the value in the dictionary is overwritten, otherwise a key-value pair is inserted.如果该部分中存在相同的键,则覆盖字典中的值,否则插入键值对。

The dictionary is of type IDictionary<string, object> and the read values ​​are not parsed, they are set as type string.字典的类型是IDictionary<string, object>并且读取的值没有被解析,它们被设置为类型字符串。

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

An example of use:使用示例:

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

The SortMenuOptions class contains a property named DropDownBtnHtmlAttribute of type Dictionary<string, object> . SortMenuOptions类包含一个名为DropDownBtnHtmlAttribute的属性,其类型为Dictionary<string, object>

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

The better way for me without changing appsetting:不更改应用程序设置对我来说更好的方法:

"CustomSection": {
    "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 : Dictionary<string, string> {}

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

//Inject an IOptions instance
public HomeController(IOptions<CustomSection> options) 
{
    var settings = options.Value;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 appsetting.json如何在多个项目.net核心中工作? - How appsetting.json works in multiple project .net core? 将值保存到 appsetting..NET 核心中的 json - Saving values to appsetting.json in .NET Core 来自 appsetting.json (.NET Core) 的 WCF 服务客户端配置 - WCF service client configuration from appsetting.json (.NET Core) 通过appsetting.json的CORS Asp.Net Core - CORS Asp.Net Core through the appsetting.json 如何访问 .Net Core 中 AuthorizeAttribute 类中的 appsetting.json 参数 - How do you access appsetting.json parameters in an AuthorizeAttribute class in .Net Core 如何在 .net 核心 api 项目中的 appsetting.json 文件中读取多个连接字符串 - How to read multiple connectionstrings in appsetting.json file in .net core api project 在.NET CORE中,如何执行XUnit测试以检查和验证从AppSetting.json加载的正确信息 - In .NET CORE, How to perform XUnit test to check and validate correct information loading from AppSetting.json 如何将值更新到 appsetting.json? - How to update values into appsetting.json? 从类库访问Asp.net-core中的appsetting.json - Access from class library to appsetting.json in Asp.net-core ASP.NET Core-每个租户的IOptions,每个租户或Vault的appsetting.json - ASP.NET Core - IOptions per tenant, appsetting.json per tenant or Vault
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM