Dotnet configuration source code:https://github.com/dotnet/runtime/tree/master/src/libraries/In which Microsoft.Extensions.Options Opening item
Options official document:
Nuget package:Microsoft.Extensions.Options
It is suggested to master the following:
- Dependency injection:
- Configuration:
introduce
Options
Provides strongly typed access to configuration data
Options
Provides a mechanism for validating options
Configure
First declare an option class
public class MyOption
{
public string A { get; set; }
public string B { get; set; }
}
useConfigure
The extension method configures the option class
var serviceCollection = new ServiceCollection();
//Configure myoption
serviceCollection.Configure(n =>
{
n.A = "A Value";
n.B = "B Value";
});
var serviceProvider = serviceCollection.BuildServiceProvider();
obtainIOptions
Option service
var myOption = serviceProvider.GetRequiredService>();
MyOption myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A);
Console.WriteLine(myOptionValue.B);
stay Aps.Net Use in
to configure
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.Configure(option =>
{
option.A = "A Value";
option.B = "A Value";
});
}
injectionIoption
[Route("Home")]
public class HomeController : ControllerBase
{
private readonly MyOption _myOption;
public HomeController(IOptions myOptions)
{
_myOption = myOptions.Value;
}
[HttpGet]
public string GetAsync()
{
return $"A:{_myOption.A},B:{_myOption.B}";
}
}
Binding configuration, usingIConfiguration
To configure options
Nuget package:Microsoft.Extensions.Options.ConfigurationExtensions
Configure(IConfigureation configuration)
Not only the configuration will be bound, but also the notification of changes to the configuration file will be addedIOptionsMonitor
Recalculation options
example:
appsettings.json
{
"MySetting": {
"A": "A Value",
"B": "B Value"
}
}
C#
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var serviceCollection = new ServiceCollection();
serviceCollection.Configure(configuration.GetSection("MySetting"));
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService>();
var myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A);
Console.WriteLine(myOptionValue.B);
PostConfigure
PostConfigure
Will be inConfigure
Then configure it
example:
var serviceCollection = new ServiceCollection();
serviceCollection.PostConfigure(option =>
{
option.B = "PostConfigure B Value";
});
serviceCollection.Configure(n =>
{
n.A = "A Value";
n.B = "B Value";
});
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService>();
MyOption myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A); // A Value
Console.WriteLine(myOptionValue.B); // PostConfigure B Value
Naming options
You can name options
The default option name is an empty string
IOptions
Getting naming options is not supported, only default naming options can be obtained
have access toIOptionsSnapshot
、IOptionsMonitor
For naming options
IOptionsSnapshot
HeirsIOptions
And addedGet(string optionName)
Method to get the naming options
IOptionsMonitor
OfCurrentValue
Property is used to get the default options,Get(string optionName)
Method to get the naming options
example:
var serviceCollection = new ServiceCollection();
//Configure myoption
serviceCollection.Configure(n =>
{
n.A = "A Value";
n.B = "B Value";
});
serviceCollection.Configure("My", n =>
{
n.A = "My:A Value";
n.B = "My:B Value";
});
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService>();
MyOption myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A); // A Value
Console.WriteLine(myOptionValue.B); // B Value
//Ioptionsnapshot get naming options
var myOption2 = serviceProvider.GetRequiredService>();
MyOption myOptionValue2 = myOption2.Get("My");
Console.WriteLine(myOptionValue2.A); // My:A Value
Console.WriteLine(myOptionValue2.B); // My:B Value
//Ioptionsmonitor gets naming options
var myOptionsMonitor = serviceProvider.GetRequiredService>();
MyOption myOptionValue3 = myOptionsMonitor.Get("My");
Console.WriteLine(myOptionValue3.A);
Console.WriteLine(myOptionValue3.B);
ConfigureAll、PostConfigureAll
ConfigureAll
、PostConfigureAll
All named configurations can be configured
example:
var serviceCollection = new ServiceCollection();
serviceCollection.ConfigureAll(n =>
{
n.A = "A Value,Config By ConfigureAll";
});
//Configure myoption
serviceCollection.Configure(n =>
{
n.B = "B Value";
});
serviceCollection.Configure("My", n =>
{
n.B = "My:B Value";
});
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService>();
MyOption myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A); // A Value,Config By ConfigureAll
Console.WriteLine(myOptionValue.B); // B Value
var myOption2 = serviceProvider.GetRequiredService>();
MyOption myOptionValue2 = myOption2.Get("My");
Console.WriteLine(myOptionValue2.A); // A Value,Config By ConfigureAll
Console.WriteLine(myOptionValue2.B); // My:B Value
IOptions、IOptionsSnapshot、IOptionsMonitor
IOptions
- Options are evaluated only once
- Naming options are not supported
- Singleton services can be injected into any service lifetime
IOptionsSnapshot
- Multiple options are counted and should be recalculated on each request
- Registered as in scope and therefore cannot be injected into a single instance service
- Support naming options
IOptionsMonitor
:
- Singleton services can be injected into any service lifetime
- Support change notification (such as profile change notification)
- Support naming options
- Support overload configuration
- Selective option invalidation (ioptionsmonitorcache))
IOptionsFactory
Responsible for creating and calculating option instances,IOptions
、IOptionsSnapshot
、IOptionsMonitor
All use it to create option instances
Contrast example:
appsettings.json
{
"MySetting": {
"B": "B 1"
}
}
C# Startup
public class Startup
{
public IConfiguration Configuration { get; }
public Startup( IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.Configure(option => { option.A = DateTime.Now.ToString(CultureInfo.CurrentCulture); });
services.Configure(Configuration.GetSection("MySetting"));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(options => { options.MapControllers(); });
}
}
C# HomeController
[Route("Home")]
public class HomeController : ControllerBase
{
public IOptions MyOptions { get; }
public IOptionsSnapshot MyOptionsSnapshot { get; }
public IOptionsMonitor MyOptionsMonitor { get; }
public IServiceProvider ServiceProvider { get; }
public IWebHostEnvironment WebHostEnvironment { get; }
public HomeController(
IOptions myOptions,
IOptionsSnapshot myOptionsSnapshot,
IOptionsMonitor myOptionsMonitor,
IServiceProvider serviceProvider,
IWebHostEnvironment webHostEnvironment
)
{
MyOptions = myOptions;
MyOptionsSnapshot = myOptionsSnapshot;
MyOptionsMonitor = myOptionsMonitor;
ServiceProvider = serviceProvider;
WebHostEnvironment = webHostEnvironment;
}
[HttpGet]
public string GetAsync()
{
Console.WriteLine($"MyOption A:{MyOptions.Value.A}");
Console.WriteLine($"MyOption B:{MyOptions.Value.B}");
Console.WriteLine($"MyOptionsSnapshot A:{MyOptionsSnapshot.Value.A}");
Console.WriteLine($"MyOptionsSnapshot B:{MyOptionsSnapshot.Value.B}");
Console.WriteLine($"MyOptionsMonitor A:{MyOptionsMonitor.CurrentValue.A}");
Console.WriteLine($"MyOptionsMonitor B:{MyOptionsMonitor.CurrentValue.B}");
//Change appsetting configuration file, penalty file change notification (JSON file configuration needs to enable change overload)
System.IO.File.WriteAllText(WebHostEnvironment.ContentRootPath + "/appsettings.json",
JsonSerializer.Serialize(new{
MySetting = new
{
B = "B 2"
}
})
);
var timer = new Timer(2000);
timer.Start();
timer.Elapsed += (sender, e) =>
{
Console.WriteLine($"MyOption2 A:{MyOptions.Value.A}");
Console.WriteLine($"MyOption2 B:{MyOptions.Value.B}");
Console.WriteLine($"MyOptionsSnapshot2 A:{MyOptionsSnapshot.Value.A}");
Console.WriteLine($"MyOptionsSnapshot2 B:{MyOptionsSnapshot.Value.B}");
Console.WriteLine($"MyOptionsMonitor2 A:{MyOptionsMonitor.CurrentValue.A}");
Console.WriteLine($"MyOptionsMonitor2 B:{MyOptionsMonitor.CurrentValue.B}");
timer.Stop();
};
return "Hello";
}
}
The console prints the following information:
First request:
MyOption A:10/23/2020 11:48:37 PM
MyOption B:B 1
MyOptionsSnapshot A:10/23/2020 11:48:37 PM
MyOptionsSnapshot B:B 1
MyOptionsMonitor A:10/23/2020 11:48:37 PM
MyOptionsMonitor B:B 1
Two seconds later
Myoption2 A: 10 / 23 / 2020 11:48:37 PM / / unchanged, because ioptions are only calculated once
Myoption2 B: B 1 / / does not change, because ioptions are only calculated once
Myoptions snapshot 2 A: 10 / 23 / 2020 11:48:37 PM / / unchanged, because ioptionsnapshot is calculated once per request
Myoptions snapshot 2 B: B 1 / / does not change, because ioptionsnapshot is calculated once per request
Myoptionsmonitor2 A: 10 / 23 / 2020 11:48:37 PM / / no change, because ioptionsmonitor did not receive the change notification of key a
Myoptionsmonitor2 B: B 2 / / changed because ioptionsmonitor received notification of file configuration changes
Second request:
Myoption A: 10 / 23 / 2020 11:48:37 PM / / unchanged, because ioptions will only be calculated once
Myoption B: B 1 / / doesn’t change, because ioptions are only calculated once
Myoptionssnapshot A: 10 / 23 / 2020 11:49:15 PM / / changed, because ioptionsnapshot is calculated every time
Myoptionssnapshot B: B 2 / / changed, because ioptionsnapshot is calculated every time it is requested
OptionBuilder
characteristic:
- Simplifies the process of creating named options because it is only initial
AddOptions(string optionsName)
A single parameter of the call, which does not appear in all subsequent calls - Can use dependencies during configuration options
- Ability to validate options
Not usedOptionsBuilder
var serviceCollection = new ServiceCollection();
serviceCollection.PostConfigure("My",n =>
{
n.A = n.A + "_Stuff";
n.B = "B";
});
serviceCollection.Configure("My", n => { n.A = "A"; });
useOptionsBuilder
adoptAddOptions(string optionsName)
obtainOptionsBuilder
var serviceCollection = new ServiceCollection();
serviceCollection.AddOptions("My")
.PostConfigure(n =>
{
n.A = n.A + "_Stuff";
n.B = "B";
})
.Configure(n => { n.A = "A"; });
Option dependency
OptionBuilder
OfConfigure
Up to five generic parameters are supported, which represent the dependency of options
var serviceCollection = new ServiceCollection();
serviceCollection.AddOptions("My")
.Configure((option, configuration) =>
{
option.A = "A";
option.B = configuration["B"];
});
Option validation
OptionBuilder
OfValidate
The option can be validated, which will be verified when the option is obtained. If the validation fails, an exception will be thrown
Validate
The second parameter of can customize the validation error message
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(_ => configuration);
serviceCollection.AddOptions()
.Configure((option, configuration) =>
{
option.A = "A2";
option.B = configuration["B"];
})
. validate (options = > options. B! = null, "B cannot be empty"); // the second parameter is used to customize the validation error information
. validate (options = > options. A! = null, "a cannot be empty"); // the second parameter is used to customize the validation error message
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService >(); // if the validation fails, an exception will be thrown
Option validation using properties
Nuget package:Microsoft.Extensions.Options.DataAnnotations
example:
appsettings.json
{
"MySetting": {
"A": "A Value",
"B": "B Value"
}
}
C#
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var serviceCollection = new ServiceCollection();
serviceCollection.Configure(configuration.GetSection("MySetting"));
serviceCollection.AddOptions()
. validatedata annotations(); // use attributes for option validation
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService>();
var myOptionValue = myOption.Value;
Console.WriteLine(myOptionValue.A);
Console.WriteLine(myOptionValue.B);
ConfiguOptions
ConfiguOptions
Used to register in a dependency containerIConfigureOptions
、IPostConfigureOptions
andIValidateOptions
Implementation of (if the incoming type implements them)
Configure
、PostConfigure
The essence of configuring options is to register in the dependency containerIConfigureOptions
Implementation of
OptionBuilder
OfValidate
The essence of functions is registrationIValidateOptions
Implementation of
So we can also register manuallyIConfigureOptions
One advantage of this is that dependency can be injected
be careful:
serviceCollection.AddOptions()
Function is used to registerIOptions
、IOptionsSnapshot
、IOptionsMonitor
、IOptionsFactory
、IOptionsMonitorCache
Implementation of
useserviceCollection.Configure
Functions such asserviceCollection.AddOptions()
, so you don’t need to call it
Here we inject it manuallyIConfigureOptions
So call it manually
Example 1:
C# 1
public class MyConfigureOption : IConfigureOptions
{
public IConfiguration Configuration { get; }
public MyConfigureOption(IConfiguration configuration)
{
Configuration = configuration;
}
public void Configure(MyOption options)
{
options.A = "A Value";
options.B = Configuration["B"];
}
}
C# 2
/// appsettings.json:{"B": "B Value"}
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(_ => configuration);
serviceCollection.AddOptions();
serviceCollection.AddTransient, MyConfigureOption>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService>();
Console.WriteLine(myOption.Value.A); // A Value
Console.WriteLine(myOption.Value.B); // B Value
Example 2:
Can be directly inherited fromConfigureNamedOptions
To implement named configuration
C# 1
public class MyConfigureOption : ConfigureNamedOptions
{
public MyConfigureOption(IConfiguration configuration)
: base("My", options =>
{
options.A = "A Value";
options.B = configuration["B"];
})
{
}
}
C# 2
/// appsettings.json:{"B": "B Value"}
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(_ => configuration);
serviceCollection.AddOptions();
serviceCollection.AddTransient, MyConfigureOption>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService>();
var myOptionValue = myOption.Get("My");
Console.WriteLine(myOptionValue.A); // A Value
Console.WriteLine(myOptionValue.B); // B Value
Example 3:
It can be realizedIValidateOptions
To verify the options
public class MyConfigureOption : ConfigureNamedOptions, IValidateOptions
{
public MyConfigureOption(IConfiguration configuration)
: base("My", options =>
{
options.A = "A Value";
options.B = configuration["B"];
})
{
}
public ValidateOptionsResult Validate(string name, MyOption options)
{
if (name != "My")
{
return ValidateOptionsResult.Skip;
}
if (options.B == null)
{
return V alidateOptionsResult.Fail ("B cannot be empty");
}
else
{
return ValidateOptionsResult.Success;
}
}
}
C# 2
/// appsettings.json:{"B": "B Value"}
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton(_ => configuration);
serviceCollection.AddOptions();
serviceCollection.AddTransient, MyConfigureOption>();
serviceCollection.AddTransient, MyConfigureOption>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var myOption = serviceProvider.GetRequiredService>();
var myOptionValue = myOption.Get("My");
Console.WriteLine(myOptionValue.A);
Console.WriteLine(myOptionValue.B);
useConfiguOptions
Replace manual registrationIConfigureOptions
、IPostConfigureOptions
andIValidateOptions
In the above instance, you need to manually specify the service class to be registered. In instance 3, you need to register twice, and use theConfiguOptions
Can help you automatically register them
The following code in example 3
serviceCollection.AddTransient, MyConfigureOption>();
serviceCollection.AddTransient, MyConfigureOption>();
You can replace the code
serviceCollection.ConfigureOptions();