by Matthew Thornton
in Open Source
on 28th Dec 2016
Estimated reading time: 15 minutes
Here at Winton we like our application configuration to be:
That’s why we have chosen to use git as the configuration source, Consul as the delivery mechanism and git2consul as the bridge between them. There’s a great blog post here about why git2consul was developed to provide a configuration system that meets the above requirements.
We also like to write many of our web services using Asp.Net Core, the new open source and cross platform version of Asp.Net. So the only missing ingredient was a means of loading configuration from Consul in an Asp.Net Core app. Luckily, Asp.Net Core has an excellent, extensible and open source configuration module.
This made it really easy to write an extension to load config from Consul.
We’ve decided to give this code back to the open source community as a package called Winton.Extensions.Configuration.Consul.
The project is up on GitHub and the package is distributed via NuGet.
If you haven't set up Consul before, there's an easy to follow guide on their website on how to get up and running.
Just add the package Winton.Extensions.Configuration.Consul to the dependencies section of your app’s project.json file like so:
Winton.Extensions.Configuration.Consul exposes an extension method to the ConfigurationBuilder in the same way that the configuration providers in Microsoft.Extensions.Configuration do.
The snippet below shows the minimal setup necessary for an Asp.Net application:
In its simplest form we just need to pass it the name of the key under which our configuration is stored in Consul and a CancellationToken.
We can also make use of the IHostingEnvironment that is injected into Startup to create a key that changes dynamically in each environment that our application runs in. This provides an easy way to separate config for development, staging and production environments for example.
You can read more about different environments in Asp.Net here.
Assuming we have an instance of Consul running on localhost and listening on the default port. Then, if our application was called Website and it was running in the Staging environment, this would load our configuration by reading the value from the key Website/Staging/appsettings.json and parse it as if it were a json file.
Finally, we need to ensure that we cancel any pending requests with Consul when the application is shutting down. This is easily done by registering a method on IApplicationLifetime.ApplicationStopping in the Configure method of Startup.
It looks something like this:
An overload for AddConsul is also provided that takes as a third parameter an Action<IConsulConfigurationSource> options. This allows us to specify a multitude of options, including a different host or port for the instance of Consul we would like to connect to, or how we would like to handle exceptions that might be thrown or a different file parser to use for, say, XML or YAML.
For more details see the documentation on the GitHub project site.
The options parameter also allows us to specify if we would like to watch the key in Consul for changes and automatically reload the configuration when this happens. To do this we just change the code in Startup as follows:
Then we can use the static ChangeToken.OnChange method from Microsoft.Extensions.Primitives to react to configuration changes as follows:
This is just how we would do it if we were using any of the configuration providers found in Microsoft.Extensions.Configuration. The configuration sources are nicely decoupled from how they are used within the application; the rest of the application doesn't need to know how the configuration was loaded.
A word of caution here though. If you’re using strongly typed config options from Microsoft.Extensions.Options then you’ll need to re-bind your objects manually on reload. This is a problem that applies to .NET config in general, whatever provider you’re using.
If you'd like a more complete example of this library in action, check out the example website in the project on GitHub.
We’re giving this project back to the open source community by putting it up on GitHub. We’d love your input, feedback and contributions. If you have ideas for improvements, or if you’ve spotted a bug, then please open an issue and we can work together to get your features and fixes included. For more information on contributing to the project see the contributing guidelines.
Do you like to contribute code, but don’t have any specific improvements in mind? At present this library only supports config in json format, but we’d love to support more formats out of the box. All you need to do is implement Winton.Extensions.Configuration.Consul.Parsers.IConfigurationParser for your config format of choice and open a pull request.
Having the configuration files stored in a Git gives us change tracking and versioning of our configuration, and by putting it in a separate repository to the application's source code it can be owned by the business and updated independently of application releases.
Consul then gives us a robust, scalable means of accessing this configuration and git2consul takes care of ensuring that when git is updated, those changes are available in Consul.
Finally, this library provides the last piece of the puzzle by allowing us to leverage this configuration system in our .NET Core applications.
Tags: code technology winton