.NET 6 implementing a custom configuration provider
Configuration providers allow application configuration to be loaded from various sources like environment variables, command line arguments, azure key vault, etc… The standard providers are very powerful but what happens when your app relies on configuration that’s stored by another service and only accessed via API?
The obvious answer is to interact with the configuration API directly, cache the result and then check cache going forward and fallback to the API only when the cache expires. This would look something like this:
This approach works but puts more burden on the developer of the order service. They need to be aware of the configuration service and how its invoked, decide what to do when the API call fails, and implement a caching layer if it doesn’t already exists. These aren’t complex problems but in the end it distracts the developer from their goal of accepting order requests.
How can this be improved?
Custom configuration providers are a great option to help reduce the complexity of reading configuration data from an external source like a REST API, database or any other remote resource. It will create a consistent feel within the application when accessing config data regardless of where its stored and will remove the need of an in memory cache (since the cache provider does this behind the scenes for us).
To illustrate how to create and use a custom configuration provider I’ve created a demo application which consists of two projects:
The tenant API is responsible for storing and providing access to a tenants data. Each tenant exposed by this service will have an ID and a list of allowed shipping methods that can be used in order requests.
The order API is responsible for accepting order requests and validating that the shipping method specified in the request is one of the allowed shipping methods for the calling tenant.
The code is intended to achieve the following architecture
To start the tenant service will need to expose an API that will return a list of all tenants with their ID and allowed shipping methods. The response from this service will be:
The implementation of the controller is:
Now that the tenant controller is defined the remaining work will be done in the OrderApi project. The first step is to add a new configuration provider which will inherit from Microsoft.Extensions.Configuration.ConfigurationProvider. This will be the class responsible for interacting with the tenant API that was previously created.
Now that the configuration provider is defined an configuration source will need to be added which is responsible for creating the provider and is what allows the provider to be registered with the configuration manager.
To simplify registration an extension method will be added which is what will eventually be used in program.cs.
In program.cs a single line will be added to register the new provider.
The full Program.cs is:
Now that the application is configured the tenant settings will be available in IConfiguration just as if they were loaded from appsettings.json or environment variables and can now be used in the order controller to validate that order requests have a valid shipping method defined.
Custom configuration providers provide extensibility of .NET configuration allowing developers to load configuration from any source.