Intro to Distributed Config with Consul on ASP.NET COre

Consul is an open source service discovery and configuration server built by HashiCorp and is highly regarded amongst the broad software development community. 

image

We are researching options for common shared services which can be used across multiple platforms at work and this one seemed to fit the bill for distributed configuration amongst other features. 

Consul provides open-source SDKs for many platforms and I was happy to find a Consul.NET C# client listed on their website.   The SDK is distributed via Nuget as you would expect:

image

Starting Consul

Their Github page for the .NET SDK also provides steps to get started which begin with running Consul locally in development mode from the commandline.  For the Docker-indoctrinated the concept of running something locally/manually seems utterly ridiculous. Again, as expected, they also provide a Docker image of Consul server which in my opinion is more convenient. 

$ docker run -p 8500:8500 -d --name=dev-consul consul

My last blog post describes how to access the Consul instance when running Docker Toolbox on Windows 7.

ASP.NET Core Configuration

The Configuration subsystem was completely rewritten in .NET Core and is much nicer.  You should check it out if you haven’t seen it yet:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration

After adding all the appropriate config-related dependencies (see in link above), we can create a simple class to hold our configuration data:

public class ConfigData 
{ 
	public string ServiceUrl { get; set; } 
} 

Next we can instruct ASP.NET to fill that class using the Configuration subsystem in the Startup class:

        public async void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddOptions();
            services.Configure<ConfigData>(Configuration);

This will use values from the web.config or any json setting files we have configured.

Consul Integration

Additionally, we want to update our configuration based on values from Consul.  First we need to add the Consul Nuget package to our project:

PM> install-package Consul
Retrieving package 'Consul 0.7.0.5' from 'nuget.org'.
  GET https://www.nuget.org/api/v2/Packages(Id='Consul',Version='0.7.0.5')
  OK https://www.nuget.org/api/v2/Packages(Id='Consul',Version='0.7.0.5') 61ms
  GET https://www.nuget.org/api/v2/package/Consul/0.7.0.5
  OK https://www.nuget.org/api/v2/package/Consul/0.7.0.5 385ms
Installing Consul 0.7.0.5.
Installing NuGet package Consul.0.7.0.5.
Successfully installed 'Consul 0.7.0.5' to ConsulSpike.AspNetCore
Executing nuget actions took 825.92 ms
Time Elapsed: 00:00:01.3042688

Next we will add another call to services.Configure in the Startup class to utilize the Consul SDK to fill the ConfigData class:

            services.Configure<ConfigData>(Configuration);
            services.Configure<ConfigData>(async config => {                
                using (var client = new ConsulClient(clientConfig => clientConfig.Address = new Uri("http://192.168.99.100:8500/")))
                {
                    var getPair = await client.KV.Get("serviceUrl");
                    if (getPair.Response != null)
                    {
                        var serviceUrl = Encoding.UTF8.GetString(getPair.Response.Value, 0, getPair.Response.Value.Length);
                        config.ServiceUrl = serviceUrl;
                    }
                }
            });

Then we need to use the setting in one of our controller actions.  Again ASP.NET Core includes dependency injection by default and provides Configuration data through the IOptions interface:

    public class HomeController : Controller
    {
        private IOptions<ConfigData> _configData;

        public HomeController(IOptions<ConfigData> configData)
        {
            _configData = configData;
        }
        public async Task<IActionResult> Math(string operation, string inputs)
        {
            var result = string.Empty;

            using (var client = new RestClient(_configData.Value.ServiceUrl))
...

Lastly we can open the Consul web interface and add our new config setting for “serviceUrl”.

image

More to Come

I will keep hacking around with this spike on Github and blog more about my findings.  The next step is to create a custom ASP.NET ConfigurationProvider so we can easily add a generic Consul configuration provider in Startup similiar to AddJsonFile for example.  Stay tuned…

https://github.com/rschiefer/ConsulSpike

Hope this was helpful, let me know in the comments below.

UPDATE 1/17/2017 – Winton Technology has already provided a ConfigurationProvider you can use.  Check out their blog post – https://tech.winton.com/blog/2016/12/configuring-net-core-applications-using-consul.

4 thoughts on “Intro to Distributed Config with Consul on ASP.NET COre”

Leave a Reply