Configuration settings is always a thorny subject. That's because different developers have different preferences on how to do this. In the .NET world, you have the
web.config depending on the project type. Then you can also use ConfigR or even static XML/JSON files. Another option is to store these settings in the database. There's is no right or wrong answer and you should use whatever works best.
However, I recently started working with a new team, where things are not as straightforward when it comes to configuration settings. The application is a standard ASP.NET MVC4 with Angular.js at the top. As many web applications, the
web.config is littered with various applications settings and connections strings. I did my best to sanitize it by clearing out dead settings and by adding the appropriate transformations. Things will change again once we move to Octopus, but for now things are working OK. Nonetheless, there was one thing that wouldn't work across multiple environments. And that was the
ConnectionString defined in the
web.config. This is the current problem:
Each developer runs its own local dev setup against a local instance of SQL Server. That instance can have any name. In fact, each developer has a different instance name and/or port number. Although we use Entity Framework, this is a DatabaseFirst/CodeFirst hybrid so we cannot use EF to bootstrap stuff and take advantage of all the clever things it can do for us. Instead, we have to work with an existing database. So how do you go about ensuring that the code works consistently on each dev environment and that it doesn't break when deployed in UAT or production?
Option 1 - ignore changes to web.config [not viable]
At first we thought about not checking in changes to the web.config but this quickly got out of hand and we realized that there could be legitimate code changes that will need to be updated. So having a different connection string in the web.config for each developer doesn't work.
Option 2 - use ConfigR [not clean]
Our second option was to use ConfigR and add some logic in the file to return the appropriate connection string based on the machine name. This was immediately rejected since hardcoding machine names isn't clean. It would also mean that things could easily break or not work for new members etc
Option 3 - use Environment Variables [accepted]
The third option was to follow the #aspnetcore example and use Environment variables to store settings that were different across our environments. The code now uses the following logic
- if there is an Environment variable set, use it
- otherwise, use the
It's not implemented as gracefully as in ASP.NET Core 1.0 but it does the job equally well. Below, I've attached the code that sets the variable and then uses it in code:
Create the variable using PowerShell (cause scripting rocks!):
[Environment]::SetEnvironmentVariable("MyDbConnection", "Trusted_Connection=True; Database=MyDb; Server=.\SQL2000,14333;", "User")
The above command creates a local user environment variable with name:
C# code for initialising the database connection string:
var environmentConnectionString = Environment.GetEnvironmentVariable("MyDbConnection", EnvironmentVariableTarget.User); connectionString = !string.IsNullOrEmpty(environmentConnectionString) ? environmentConnectionString : ConfigurationManager.ConnectionStrings["MyDbConnection"].ConnectionString; //Do what you wish with --> connectionString;
This way, we don't need to worry about accidental check-ins of wrong files and it keeps the code and our setup clean and consistent. It may not be the ideal way of doing this, but given the current setup, it's a nice, consice and workable solution.
Feel free to let me know if you've got any better ideas.