Almost every application requires some form of configuration information. This information can be as simple as a database connection string or as complex as multipart and hierarchical user preference information. How and where to store an application’s configuration data are questions you often face as a developer.
Any large enterprise application has many moving blocks. They all need to be configured for a proper working of the application. As the application size increases or for scalability the same configuration has to be repeated in different applications. For most applications once the configuration has been changed the application needs to be restarted.
Sample Code (create a blank console project, add json.net nuget)
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Collections.Generic; using System.Linq; namespace CM { // configuration management API, //1. allow clients specify typesafe models for configuations //2. Store flat data on server (table) which is easy to edit //3. can be extended to have inheritance of values (overrides) //4. can be extended to lock / unlock certain property by admins etc. class Program { //Sample configuration model internal class SampleConfigModal { public SampleConfigModal() { Address = new Address(); } public string Name { get; set; } public Address Address { get; set; } public int Age { get; set; } } public class Address { public string Street { get; set; } } // this is how client api will look like static void Main(string[] args) { // sample client code var data = new SampleConfigModal() { Name = "Rajnish", Age = 18, Address = new Address() { Street = "Oxley" } }; // save Configuration SaveConfiguration("app", "section", data); //get Configuration var data2 = GetConfiguration("app", "section"); } // Client side framework api -> call to rest end point private static T GetConfiguration(string appName, string SectionName) where T : new() { var defaultValue = new T(); var samplePayload = JsonConvert.SerializeObject(defaultValue); var payload = GetConfiguration(appName, SectionName, samplePayload); return JsonConvert.DeserializeObject(payload); } // Client side framework api -> call to rest end point private static void SaveConfiguration(string appName, string SectionName, T data) { var payload = Newtonsoft.Json.JsonConvert.SerializeObject(data); SaveConfigurationa(appName, SectionName, payload); } //---------------------------------------- Server Code -------------------------- //-------------- server has no knowledge of configuration structure or model private static Dictionary<string, string> storage; private static void SaveConfigurationa(string appName, string SectionName, string payload, string enumForHierarchyLevel = null) { // transformer var section = string.Format("{0}.{1}", appName, SectionName); var data = (JObject)JsonConvert.DeserializeObject(payload); var keyValueData = Flatten(data, section); // check if user has permission for level overrides // store with proper overides // store the flat list in sql or data //| KEY | |Value| |OverrideType| - default,sysadmin,appadmin,groups,user etc //app.section.Name, Rajnish //app.section.Address.Street, Oxley //app.section.Age, 18 storage = keyValueData; } private static string GetConfiguration(string appName, string SectionName, string samplePayload) { var section = string.Format("{0}.{1}", appName, SectionName); var data = (JObject)JsonConvert.DeserializeObject(samplePayload); var keyValueSample = Flatten(data, section); // update data from sql or data store // apply property override rules and get value from overrides if exists var keyValueData = keyValueSample.Select(x => new KeyValuePair<string, string>(x.Key, storage[x.Key])); //read these //app.section.Name, Rajnish //app.section.Address.Street, Oxley //app.section.Age, 18 UnFlatten(data, section, keyValueData); var formatedData = JsonConvert.SerializeObject(data); /* * { "Name": "Rajnish", "Address": { "Street": "Oxley" }, "Age": "18" } * */ return formatedData; } // Server side json helper private static void UnFlatten(JObject jsonObject, string prefix, IEnumerable<KeyValuePair<string, string>> data) { foreach (var item in data) { var keyName = item.Key.Substring(prefix.Length + 1); var storageValue = item.Value; if (keyName.Contains(".")) { var keys = keyName.Split('.'); var jtoken = (JToken)jsonObject; foreach (var k in keys) { jtoken = jtoken.SelectToken(k); } ((JValue)jtoken).Value = storageValue; } else { jsonObject[keyName] = storageValue; } } } private static Dictionary<string, string> Flatten(JObject jsonObject, string prefix) { IEnumerable jTokens = jsonObject.Descendants().Where(p => p.Count() == 0); Dictionary<string, string> results = jTokens.Aggregate(new Dictionary<string, string>(), (properties, jToken) => { properties.Add(string.Format("{0}.{1}", prefix, jToken.Path), jToken.ToString()); return properties; }); return results; } } }