OptionSettings is a simple feature that allows you to register your configuration/setting classes without having to add them to the Program / Startup file, keeping them clean and smooth.
- Follow best practices using Options Pattern
- Cleaner and readable Program / Startup files, keep them small.
- Make your configuration/setting classes ready-to-use just as you finish creating them, you don't even need to go into the Program / Startup file.
- .NET CLI
dotnet add package AMillo.OptionSettings --version 1.0.0
- Package Manager
Install-Package AMillo.OptionSettings -Version 1.0.0
-
Add the following using directive on your Program.cs / Startup.cs file
using AMillo.OptionSettings.Extensions.DependencyInjection;
-
Call the AddOptionSettings extension method using one of the following overloads
- builder.AddOptionSettings()
//Add all configuration classes marked with [OptionSettings] attribute from all assemblies in the current AppDomain //Uses builder.Configuration by default to bind the settings builder.AddOptionSettings();
- builder.AddOptionSettingsFromAssemblies(IEnumerable assemblies)
//Add all configuration classes marked with [OptionSettings] attribute from specified assemblies //Uses builder.Configuration by default to bind the settings builder.AddOptionSettingsFromAssemblies(AppDomain.CurrentDomain.GetAssemblies());
- builder.AddOptionSettingsFromAssembly(Assembly assembly)
//Add all configuration classes marked with [OptionSettings] attribute from specified assembly //Uses builder.Configuration by default to bind the settings builder.AddOptionSettingsFromAssembly(typeof(Program).Assembly);
- builder.Services.AddOptionSettings(IConfiguration configuration)
//Add all configuration classes marked with [OptionSettings] attribute from all assemblies in the current AppDomain //Also uses the specified configuration to bind the settings builder.Services.AddOptionSettings(builder.Configuration);
- builder.Services.AddOptionSettingsFromAssembly(Assembly assembly, IConfiguration configuration)
//Add all configuration classes marked with [OptionSettings] attribute from specified assembly //Also uses the specified configuration to bind the settings builder.Services.AddOptionSettingsFromAssembly(typeof(Program).Assembly, builder.Configuration);
- builder.Services.AddOptionSettingsFromAssemblies(IEnumerable assemblies, IConfiguration configuration)
//Add all configuration classes marked with [OptionSettings] attribute from specified assemblies //Also uses the specified configuration to bind the settings builder.Services.AddOptionSettingsFromAssemblies(AppDomain.CurrentDomain.GetAssemblies(), builder.Configuration);
- builder.AddOptionSettings()
-
Mark your configuration class with the [OptionSettings] attribute.
using AMillo.OptionSettings.Attributes; [OptionSettings(sectionName: Constants.AppSettings.Sample)] internal sealed class SampleConfiguration { public string SampleKey { get; set; } = string.Empty; public int SampleNumber { get; set; } = 0; }
-
That's it! Now you can start using you configuration class following the Options pattern with IOptions, IOptionsMonitor or IOptionsSnapshot.
You need to specify the "sectionName" to the attribute's constructor, this value needs to match the section in your AppSettings file from where you want your configuration/setting class get configured.
This is how the AppSettings.json file looks like for the previous example:
"SampleConfiguration": {
"SampleKey": "SomeKey",
"SampleNumber": 1234567890
}OptionSettings has full support for you to validate your configuration classes as much as you like.
- ValidationMode.None: This is the default, with this option your configuration class will not be validated at all.
using AMillo.OptionSettings.Attributes;
using AMIllo.OptionSettings.Enums;
[OptionSettings(
sectionName: Constants.AppSettings.Sample,
ValidationMode = ValidationMode.None)]
internal sealed class SampleConfiguration { }- ValidationMode.Startup: The values will be validated when the application starts.
using AMillo.OptionSettings.Attributes;
using AMIllo.OptionSettings.Enums;
[OptionSettings(
sectionName: Constants.AppSettings.Sample,
ValidationMode = ValidationMode.Startup)]
internal sealed class SampleConfiguration { }- ValidationMode.Runtime: The values will be validated on runtime when trying to access the configuration class.
using AMillo.OptionSettings.Attributes;
using AMIllo.OptionSettings.Enums;
[OptionSettings(
sectionName: Constants.AppSettings.Sample,
ValidationMode = ValidationMode.Runtime)]
internal sealed class SampleConfiguration { }NOTE: Personally. I recommend using ValidationMode.Startup so the application can not run with invalid configuration values and fails as soon as possible, at startup time.
using AMillo.OptionSettings.Attributes;
using AMIllo.OptionSettings.Enums;
using System.ComponentModel.DataAnnotations;
[OptionSettings(
sectionName: Constants.AppSettings.Sample,
ValidationMode = ValidationMode.Startup)]
internal sealed class SampleConfiguration
{
[Required]
[MaxLength(20)]
public string SampleKey { get; set; } = string.Empty;
[Required]
[Range(0, 10)]
public int SampleNumber { get; set; } = 0;
}3. You can also add multiple validation methods and mark them with the [OptionSettingsValidation] attribute. This allows you validate your configuration class values in more complex ways.
- The methods must have the following signature:
Where TOptions is your configuration class.
bool AnyMethodName(TOptions options)
- You can pass a FailureMessage to the [OptionSettingsValidation] attribute if you want to show a custom message if the validation fails.
[OptionSettingsValidation(FailureMessage = "Custom failure messsage")]
- The methods only returns true indicating the validation succeeded or false indicating the validation has failed.
- These validations methods will run depending on the value you have configured into the ValidationMode option.
using AMillo.OptionSettings.Attributes;
using AMIllo.OptionSettings.Enums;
using System.ComponentModel.DataAnnotations;
[OptionSettings(
sectionName: Constants.AppSettings.Sample,
ValidationMode = ValidationMode.Runtime)]
internal sealed class SampleConfiguration
{
[Required]
[MaxLength(20)]
public string SampleKey { get; set; } = string.Empty;
[Required]
[Range(0, 10)]
public int SampleNumber { get; set; } = 0;
public string SampleString { get; set; } = string.Empty;
[OptionSettingsValidation(FailureMessage = "SampleString can't contain vowels.")]
public static bool ValidateSampleString(SampleConfiguration options)
{
HashSet vowels = ['a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'];
foreach (char @char in options.SampleString)
{
if (vowels.Contains(@char))
{
return false;
}
}
return true;
}
[OptionSettingsValidation(FailureMessage = "SampleNumber must be 1 when SampleKey is 'one'")]
public static bool ValidateSampleNumber(SampleConfiguration options)
{
if(options.SampleKey == "one" && options.SampleNumber != 1)
{
return false;
}
return true;
}
}Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature) - Commit your Changes (
git commit -m 'Add some AmazingFeature') - Push to the Branch (
git push origin feature/AmazingFeature) - Open a Pull Request
Alejo Millo - alejo.millo@outlook.com