可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am familiar w/ loading an appsettings.json section into a strongly typed object in .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. 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?
回答1:
You can use Configuration.Bind(settings);
in startup.cs
class
And your settings class will be like
public class AppSettings
{
public Dictionary<string, string> MobileConfigInfo
{
get;
set;
}
}
Hope it helps!
回答2:
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);
});
回答3:
For others who want to convert it to a Dictionary,
sample section inside 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:
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.
回答4:
I believe you can use the following code:
var config = Configuration.GetSection("MobileConfigInfo").Get<Dictionary<string, string>>();
回答5:
By far the simplest method would be to define your configuration class to inherit from the Dictionary type you want to support.
public class MobileConfigInfo:Dictionary<string, string>{
}
Then your startup and dependency injection support would be exactly the same as for any other configuration type.
回答6:
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:
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
}
回答7:
As an example of more complex binding in ASP.Net Core 2.1; I found using the ConfigurationBuilder
.Get<T>()
method far easier to work with, as per the documention.
ASP.NET Core 1.1 and higher can use Get, which works with entire sections. Get can be more convenient than using Bind.
I bound the configuration in my Startup
method.
private Config Config { get; }
public Startup(IConfiguration Configuration)
{
Config = Configuration.Get<Config>();
}
This binds the appsettings
file:
{
"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; }
}
回答8:
I use the way below:
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"));
Usage:
private readonly Dictionary<string, string> _services;
public YourConstructor(IOptions<Dictionary<string, string>> servicesAccessor)
{
_services = servicesAccessor.Value;
}
回答9:
The only thing that worked for me (ASP.NET Core 3.0) was to add the following to the ConfigureServices
method of Startup.cs
:
services.Configure<Dictionary<string, string>>(dict => Configuration.GetSection("MySectionName").GetChildren().ToList().ForEach(c => dict[c.Key] = c.Value));