Skip to content

Easy and clean ConfigurationSettings feature to register configuration classes following the Options pattern while keeping the Program.cs / Startup.cs small and clean.

License

Notifications You must be signed in to change notification settings

AlejoMillo00/AMillo.OptionSettings

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Contributors Forks Stargazers Issues LinkedIn


OptionSettings

Report Bug · Request Feature

About The Project

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.

Getting Started

Installation

  • .NET CLI
    dotnet add package AMillo.OptionSettings --version 1.0.0
  • Package Manager
    Install-Package AMillo.OptionSettings -Version 1.0.0

Usage

  1. Add the following using directive on your Program.cs / Startup.cs file

    using AMillo.OptionSettings.Extensions.DependencyInjection;
  2. 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);
  3. 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;
       }
  4. That's it! Now you can start using you configuration class following the Options pattern with IOptions, IOptionsMonitor or IOptionsSnapshot.

Important

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
  }

Validations

OptionSettings has full support for you to validate your configuration classes as much as you like.

1. Set the ValidationMode in the [OptionSettings] attribute:

  • 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.

2. Add DataAnnotations to validate your configuration class properties:

  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:
      bool AnyMethodName(TOptions options)
    Where TOptions is your configuration class.
  • 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;
    }
  }

Contributing

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!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Contact

Alejo Millo - alejo.millo@outlook.com

About

Easy and clean ConfigurationSettings feature to register configuration classes following the Options pattern while keeping the Program.cs / Startup.cs small and clean.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Languages