Application Configuration in CSharp/.Net/.Net Core
Stick around for the end of this article for a bonus on .Net Core.
Hi, I am a developer who tends to think nihlistically about most things. Often, developers get overly excited about something which - to me is completely cumbersome and almost pointless - but to them, is a feature. Something which should not even exist - is celebrated as incredible and projects waste weeks on something which should be done easier.
One example is WCF/Web Services inside an Enterprise - why not use a database? Sure in an internet world.
Another example is the app.Config file in .Net and configuration in general. Yes, I know we are now in the world of .Net Core - but taking the philosophy I am preaching in this blog works easily as well there.
You can view my blog here Zak's blog
My Limited Company is here Info Rhino Limited
Current work
Currently, I am building an application which will generate multiple executions - dropping the same applications in different folders to permit scaling out as part of my batch execution framework. Don't worry yourself with the details or of the app(s).
Right now, I won't know exactly what is the best way to execute my application. We build in a lean way - adding as we go. Even now, I can start making decisions on how the application can start to function, and how it could function several iterations on. We are playing chess - thinking a few moves ahead, but the current move is the most important. We are not doing agile nonsense where each move is a potential rewrite.
Key goal - changing configuration should be natural
Developers shouldn't agonise over changing configuration. Configuration
should be able to evolve with the application's scalability requirements.
On projects, I have spent countless time in meetings where developers elaborate over the merits or demerits of adding or removing some configuration - what it may do to the application, regression etc.
Thinking about configuration as data
In today's day and age - data can exist anywhere and everywhere. It could be in a text file, a json file, an xml file, a web api, a database, a nosql database, documents, and many other places.
We think configuration as being the stuff which is used on application startup, is fairly static, dull and boring but at the same time, essential.
Once I think about configuration as data, I start to see the configuration as an ideal a candidate for refactoring and permitting enhanced application functionality as the application requires it.
What is configuration?
Configuration, in the .Net world, is data which exists at application build.
Yes, configuration can exist in databases and on disk, but we can consider configuration as being immutable once the application has started. We know this isn't completely true - but let's stick with that model.
What is wrong with .Net configuration
On one site, I saw project teams working on .Net applications maintaining hideously complicated configuration files - I praised the lord I was working on Business Intelligence projects. Anybody who has worked with SSIS understands how seriously SSIS takes configuration.
.Net Configuration shames people into wasting a lot of time by "doing it properly". What do we achieve at the end? A strongly typed section in a configuration file only usable within .Net - Big Deal! Not worth getting out of bed for.
A simple example of why application configuration is crap in .Net and how to fix it
Imagine we have the following settings;
Folder, Api, ParticleAccelerator.
Often, we will have to do some mapping inside the Program.Main method to do something like
var folderaccelerator = new FolderAccelerator(){Folder=ConfigurationManager.AppSettings["Folder"]}; /*etc*/
This is painful to say the least. I prefer to do something like the following;
public class Setting : ISetting
{
public FolderAccelerator folderAccelerator {get;set;} = ConfigurationManager.AppSettings["folderAccelerator"].DeserialiseObject<FolderAccelerator>();
}
Then, in our dependency binder (Nuget), we can simply do something like;
Bind<ISetting>().To<Setting>();
You may realise, I have written a wrapper around NewtonSoft's Deserialize method.
The specific application configuration key would look something like
<add key="folderAccelerator" value="['folder':'C:\somewhere', 'Api': 'http://somewhere/endpoint',
'ParticleAccelerator':'MaxiumOverdrive']"/>
Note, we can improve the appsettings key lookup by this
public class Setting : ISetting
{
public FolderAccelerator folderAccelerator {get;set;} = ConfigurationManager.AppSettings[nameof(folderAccelerator)].DeserialiseObject<FolderAccelerator>();
}
We could also write an extension method to avoid keep seeing configuration manager, but it helps us know where this comes from.
Second example of overkill with .Net System.Configuration
In no way am I criticising the creator of the following post -
https://ivankahl.com/creating-custom-configuration-sections-in-app-config/
We have all had to create custom configuration sections in .Net
In his and my world - bad
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /> </startup> <appSettings> <add key="sageCRMInstance1Name" value="AdventureHouseAppliances"/> <add key="sageCRMInstance1Server" value="192.168.23.45" /> <add key="sageCRMInstance1InstallationName" value="MainCRM"/> <add key="sageCRMInstance2Name" value="AdventureTechnology"/> <add key="sageCRMInstance2Server" value="192.168.76.2" /> </appSettings> </configuration>
In his world - great, in my world - really complicated to code for all of this
<?xml version="1.0" encoding="utf-8" ?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /> </startup> <sageCRM> <instances> <add name="AdventureHouseAppliances" server="192.168.23.45" installationName="MainCRM"/> <add name="AdventureTechnology" server="192.168.76.2"/> </instances> </sageCRM> </configuration>
Why is this bad?
Unfortunately, a lot of additional development has to be undertaken to create configuration sections which are application specific. Vendors may definitely want to create their own configuration as per that mechanism - but it is overkill for most in-house applications.
Really thinking about configuration iteratively
I imagine, you don't quite get what I have been explaining until now. So far, we have created string (serialised) versions of objects directly inside an appsettings key. This cuts out a lot of manual mapping. The real benefit is we have a lot less maintenance as our configuration changes.
If I feel an application needs to work in batch mode, or run in lots of different configuration sets, then I might do the following;
Create a commandline config switch such as
-locationOfConfig "C:\Somewhere\Processingdef.json"
We can choose to use a different binding in the dependency binder, thereby completely changing our application configuration without having to rebuild the application.
We could remove our configuration from appsettings altogether if we felt it relevant and rely upon external json files.
Start simple, sophisticate later
Below is a live configuration I am working on for my application. I don't really want to keep maintaining lots of versions of app.config, probably I will just move these into separate file(s).
<appSettings>
<add key="jobSchemaName" value="job" />
<add key="ConfigSourcePath" value="C:\InfoRhino\scraper\ScrapingEngine\Scraper\Deployment\PropertyApplications\" />
<add key="validConfigExecutableExtensions" value="[{'SeparatorAndExecutableExtension':'.exe'},{'SeparatorAndExecutableExtension':'.ps1'},{'SeparatorAndExecutableExtension':'.jar'}]" />
<add key="regexForExeNameOnly" value="(?isn-mx:((?<ExeOnly>[a-z0-9_\s]+)(?=\.)))"/>
<add key="appNameReplacementPlaceholder" value="@@"/>
<add key="solutionApplication" value="['SolutionBaseDirectory': 'C:\InfoRhino\scraper\ScrapingEngine\Scraper\IRExecutor\', 'BuiltBinaryFolderName': 'Release']"/>
<add key="ApplicationConfigMap" value="[
{'ApplicationExtension' : '.config'
, 'ConfigMap' : '@@.exe.config'
,'Description' : 'Application Configuration file'
,'ShouldCreateDummy' : true
,'CopyFromSource': false
}
,
{'ApplicationExtension' : '.nlog'
, 'ConfigMap' : 'nlog.config'
,'Description' : 'NLog logging file'
,'ShouldCreateDummy' : false
,'CopyFromSource': true
}
]"/>
Supposing, I decide to create a mini application which focuses purely on maintaining configuration? Doesn't most MVVM applications work with JSON?
For the many applications I have been buiilding for my Framework, I am likely to outsource some front-end development of my configuration when I need to.
It would be possible to simply give a development company, a JSON file as a main part of the specification.
Bonus - .Net Core
So, I won't do very much on this but all we have thought about above is still relevant in .Net Core. I find myself putting configuration in the appsettings.json file - before deciding whether to move it to a more loosely coupled location.
The JSON configuration segment inside appsettings.json
[ "CookieMessage": {
"ConfirmText": "Understood",
"UrlOfCookiePolicy": "www.inforhino.co.uk/uploads/TermsAndConditions2019.pdf",
"MessageText": "This website does not use ANY cookies. The only cookie which will be saved, will be the cookie from clicking 'Understood'."
}]
Inside the Startup.cs file
```csharp services.AddSingleton(Configuration.GetSection(nameof(CookieMessage)
).Get());
### Inside a view, where this gets used
```csharp
@inject IRWebsiteCMS.Models.Display.CookieMessage cookie
Implications are the same
So, we can start to, if we see fit open up the appsettings.json file to an MVVM application in Svelte, Knockout.js or Vue.js.
We could let an application generate json which an application could consume.
How about using Automapper to create a configuration hierarchy?
Imagine we have a base class of Setting, but map that wide class to multiple scoped classes.
Conclusion on Configuration
In 2020 - we have to wage war on herd approaches to development. Approaches which have a valid approach for 1 out of 50 times should not be the mainstay of every application. We should embrace configuration rather than see it as the unsexy part of application development.
Written with StackEdit.
Top comments (4)
In the dot net framework world I used to use App.Settings - edit in VS and have it auto-generate the settings class.
I kinda miss that in the dot net core world, where you have to write both the Json configuration and the cs class to go along with it (I know, you can auto-generate the Json from the cs and vice-versa, but still...)
Hi Zohar. Thanks for reading.
I see where you are coming from with this. But you don't get the richness of direct object mapping as you get from using key value pairs. Kind of what I see as a big win in .Net Core.
The article was more to do with thinking in terms of config as data and embracing this.
My main issue with App.Config is that to make a professional strongly typed approach involves a lot of overhead. Not only that, the xml inside the app.config file is largely unusable as it is complex xml (as opposed to nested). Using JSON does allow you quite quickly see what is going on with the object.
There is a lot about app.config to like too.
BTW - pretty sure you can still use app.config in .Net Core if you use System.Configuration? This might be one way of upgrading apps. Haven't looked into it.
I'm just ranting, I like the json configuration better than the XML because you don't have to use all the built in crap and simply keep only the things you actually want in the json itself. I totally agree that configuration is data and should be treated as such.
I knew I shouldn't have written a post on configuration. 7 views. 😝