MongoDb Configuration Provider for Asp.net Core 3.1

4 minutes to read read

Around four years ago when .Net Core was in its early stages, I wrote back a Configuration provider for .net core 1.x. This has been a long time. The package did picked up very well and there were multiple downloads and a few queries as well. Many people would never know that .net core started with json project files. But since then a lot changed and my package went obsolete.

A few days back got some time and bandwidth and wised to revise the package. This would not only update the latest package but would also help me understand what changes have been done as in framework as a whole. So, my fellow countrymen let me present you the MongoDbConfiguration Provider for .net Core (😁) /s

Read on further to get the details as I explain the “simple” steps to write a custom configuration provider for .net core 3.1.

The details of packages and repo are provided at bottom of the post.

Problems

Wider Use Cases

When writing a generic code or a nuget the most common problem is that the package should be usable to a wider set of audience. The OS libs are not born on day one in full fledge form but many ppl do start handling the problem at hand. However in many cases the lib is not evolved further. My goal her is to cover as much surface area as possible. I did tried to cover 4 different possible usage scenarios as explained below which should handle most of the basic requirements. Although i do plan to extend this further.

Lot has changed.

Yes, as expected, a LOT has changed from .net Core 1.x to 3.x. Not just project structure, but also the interfaces, methods, signatures a lot..

Lack of Documentation.

This did became one of the challenge. I tried to follow MSDN documentation, but hate to say it, it is crappy. Microsoft had put a great deal of focus on common and mostly used scenarios, but due to which the major issue that crept up is that the rare use cases, are not widely available and documented. And they remain rare.

Start Here. Extend the interfaces.

Cutting the further crap, lets pull in. There are 2 interfaces that needs to be extended in case you need to write any custom configuration provider.

IConfigurationSource

This is the innocent one. No fancy logic here. Simple interface with just one Method. But this is actually the entry point. Its responsibility is to create the actual Provider.

    public interface IConfigurationSource
    {
               IConfigurationProvider Build(IConfigurationBuilder builder);
    }

The extended class which implements this interface can be found at: https://github.com/yadavvineet/MongoDb.Asp.ConfigurationProvider/blob/master/MongoDb.Asp.ConfigurationProvider/MongoDbConfigurationSource.cs . Its a very simple class and just returns a new instance as apparently below.

public class MongoDbConfigurationSource : IConfigurationSource
    {
        private readonly MongoDbConfigOptions _options;
        public MongoDbConfigurationSource(MongoDbConfigOptions options)
        {
            _options = options;
        }

        public IConfigurationProvider Build(IConfigurationBuilder builder)
        {
            return new MongoDbConfigurationProvider(_options);
        }
    }

IConfigurationProvider – the Beast

Yes, IConfigurationProvider is the actual provider and beast. It is responsible for everything. The derived implementation is available at: https://github.com/yadavvineet/MongoDb.Asp.ConfigurationProvider/blob/master/MongoDb.Asp.ConfigurationProvider/MongoDbConfigurationProvider.cs

Lets break method by method and analyze it.

        public bool TryGet(string key, out string value)
        {
            if (_itemsCollection.ContainsKey(key))
            {
                value = _itemsCollection[key];
                return true;
            }
            value = string.Empty;
            return false;
        }

        public void Set(string key, string value)
        {
            throw new NotSupportedException("Setting a key is not supported.");
        }
        public IChangeToken GetReloadToken()
        {
            return _token;
        }

TryGet is responsible for actually returning the value of the key and its pretty straighforward.

Set is generally not supported in most cases as in most cases its read only store. However, I do wish/plan to have a future implementation for this method but there are challenges on how to serialize nested keys. So for now not implemented it.

GetReloadToken is responsible to reflect is the value changed. Basically if the value at source is changed, this should be updated. This is also planned to be updated later with hot reload functionality, but for now kept it open

        public void Load()
        {
            //code removed for Brevity 
        }

This is the crux of the provider. This is responsible for loading all the keys from the source. The code in my provider is a bit nasty in current form and needs some refactoring. I have tried to keep it simple and more readable till initially and it reflects the basic state of conditions for which values are loaded as a mirror.

Extension Methods

Once done, next step is to include the provider via source via a simple extension method written over IConfigurationBuilder.

Rest of the code along with the test app is explanatory. Only point is the way it is consumed in the target service where it is consumed. For that have a look at the Program.cs in TestWebApp. I would try to cover the cases we intend to cover.

Configuration Options

Following four methods are provided currently to load different configuration options.

  1. AllKeys – All Documents – (MongoDbConfigOptions.GetOptionsForAllKeysAllDocuments()) – Use this to read all the keys from all the documents in a collection
  2. Defined Keys – All Documents (MongoDbConfigOptions.GetOptionsForDefinedKeysAllDocuments) – Use this method to load specific set of keys (named keys) from all the documents in a collection.
  3. All Keys – Filtered Documents (MongoDbConfigOptions.GetOptionsForAllKeysFilteredDocuments) – Use this method to load all the keys from filtered document. Filter can be applied for a single set of key value pair. Example could be to look for env variables.
  4. Defined Keys – Filtered Documents (MongoDbConfigOptions.GetOptionsForDefinedKeysFilteredDocument) – Use this method to load specific set of keys from filtered document. Filter can be applied for a single set of key value pair. Example could be to look for env variables.

Resources

Nuget: https://www.nuget.org/packages/MongoDb.Asp.ConfigurationProvider/
Command:

Install-Package MongoDb.Asp.ConfigurationProvider -Version 2.0.0

Github link:

https://github.com/yadavvineet/MongoDb.Asp.ConfigurationProvider/

Please do write back in case of any comment or questions or suggestions.

PRs are welcome

1 comment

Leave a Reply

Your email address will not be published. Required fields are marked *