Manage multiple app config files during development - c#

I'm building an application that is used by several different customers. Each customer has a fair amount of custom business logic, which I have cleverly refactored out into an assembly that gets loaded at runtime. The name of that assembly, along with a number of other customer-specific settings, are stored in the application's configuration file.
Right now, here's what I have to do in order to debug the application for customer foo:
Go to the filesystem in my project directory and delete app.config
Copy app.config.foo to app.config.foo - Copy.
Rename app.config.foo - Copy as app.config.
Tell Windows that yes, I want to change the file's extension.
Switch back to Visual Studio.
Open the Settings.settings item in my project.
Click "Yes" 13 or 14 times as VS asks me if I want to use the new settings that have been changed in app.config.
Close Settings.settings.
Okay! Now I'm ready to debug!
It seems to me that the rigamarole of opening Settings.settings is, or ought to be, unnecessary: I don't need the default values in Settings.cs to be regenerated, because I don't use them. But it's the only way I know of to make VS aware of the fact that the app.config file has changed, so that the build will copy it to the output directory.
There's got to be an easier way of doing this. What is it?

You can also let Visual Studio automate Robert`s approach by:
Define a Build Configuration for each client
In the post build event, simply xcopy app.config.xxx to your bin folder. Where XXX is the name of a Build Config accessible in VS. Something like: xcopy app.config.$(ConfigurationName) $(OutDir)/app.config
VS will drop a distinct build for your clients in separate folders, aolong with the proper config file.
bin/Client1/
bin/Client2/

You can refer this post for some good practices : Managing Multiple Configuration File Environments with Pre-Build Events

Thinking about the mess of managing multiple configuration files I made this tool: http://envride.codeplex.com/
Its purpose its exactly to make it easier to manage multiple configuration files in an automated way. I would be very pleased if you would take a look at it.

A couple of people suggested using multiple VS configurations, which I think would have worked, except that it would require me to rebuild the solution every time I switched between configurations.
What I did instead seemed a little stupid while I was doing it, but I've been using it for nearly a year now and it works extremely smoothly. In my project directly, I create a separate app.config.XXX file for each customer. The actual app.config file is used solely to generate Settings.cs - it has all of the correct setting names and their default values. It doesn't get copied to the build directories, ever.
Then I wrote a little program that lets me select a customer, and that simply goes through the directories for each project and, if I selected customer XXX, copies app.config.XXX to bin\debug\myprogram.exe.config and bin\release\myprogram.exe.config. As long as this program knows where the root of the solution is (I have to be a little careful whenever I branch the code), it works like a charm.

This thread is too old to represent current tools in VS.
You can use an addon that acts similar to web.debug.config but for app.config.
https://marketplace.visualstudio.com/items?itemName=GolanAvraham.ConfigurationTransform
And for the same app.config transformations without addon.
https://www.linkedin.com/pulse/multi-appconfig-visual-studio-2017-benjamin-davis/

You may opt to define multiple Visual Studio solution configurations, one for each customer, and have customised MSBuild targets for your Windows app project.
I have documented the steps of how I handled this here. Multiple app.config files for deploying to different environments

After a little digging and work around I got my Test project working with multiple configurations,
In the Configuration Manager, create the configurations you need
Copy paste your app.config and add the name of the configuration, in my case is AHI, FIV, MGC, so my config files look like: App.AHI.config, App.MGC.config, App.FIV.Config. You can name it how ever you wanted, but keep the same convention
Add a Post-Build event. In my case it would look like: xcopy $(ProjectDir)app.$(ConfigurationName).config $(TargetDir)$(TargetName).dll.config /y
here is my post, so you can read it with more details
Running a Test Project with Multiple Configurations

Related

How is it possible to access files in project directory using relative path, regardless of executable location?

While running my project using Visual Studio, the working directory (AppDomain.CurrentDomain.BaseDirectory) is {ProjectDirectoryPath}\bin\Debug\netcoreapp2.0; but while running the project from its publish folder (after publishing it), the working directory is {PublishDirectoryPath}. All project configuration and data files are located under {ProjectDirectoryPath} and {PublishDirectoryPath} in the same tree structure. What it means is that whenever I'm running the project using Visual Studio, I should prefix the path of each of the files with ../../../.
My current solution is using the following function whenever accessing a file in the project directory:
public static string Root()
{
string root = AppDomain.CurrentDomain.BaseDirectory;
if (root.EndsWith("Debug\\netcoreapp2.0\\"))
root = root + Slash("../../..");
return root;
}
However, it feels to me that there must be some better way to solve this, since using files located under the project directory is nothing unusual (though it's more common to store configuration and data files under %AppData% or /home). So it doesn't seem right that so many developers would really implement a solution like this to something so common.
What am I missing?
Typically, any constants that your application is dependent on that could change are added to a web.config/app.config file; so that you don't need to recompile the code to change these values. An exception would be a service or library that would require consumers to provide the data via parameters.
When you store paths in a config file, you can use web.config/app.config transforms to change the values based on the build configurations. This allows you to supply different values to your config file settings based on the environment you deploy to.
I posted this question after hours of research. Even after posting it I continued searching for a solution. I saw a lot of threads about this issue, and a lot of solutions that didn't work in my case. Now I stumbled across this, and I used the second approach. Using this solution it works.
It seems so bizarre to me that the access to something so basic would be so non-intuitive. Unfortunately, .NET Core is yet not mature enough.

Brand specific web.config sections automation

I am doing some research on how to make web.config dynamic per environment and brand. We have web.config different for different environments and brands.
Right now we make copy of it store a separate files and finally pick it manually and deploy.
I am finding various arcticles to do this and one the below has one solution.
http://www.hanselman.com/blog/ManagingMultipleConfigurationFileEnvironmentsWithPreBuildEvents.aspx
I don't want any code or anything like but need some references if there are any other best industry practices
See http://msdn.microsoft.com/en-us/library/dd465326(v=vs.110).aspx for web.config transformations. Same concept. You have a base config file and then have specific nested config files per environment, brand or both. Depending how you deploy your application can affect how many web.config you have. In newer visual studio you cannpreview the changes as well by clicking on the nested web.config in solution explorer
App.config transformations aren't supported out of the box but with some msbuild events that's how wendo these ones

Configuration files per environment

I'm working on a project with several environments (Local,Development,Main,Prod,Live) that have several config files (Web, ConnectionStrings Windsor, Smtp, Appsettings, Nlog, etc).
The current strategy used is to have one of these config for each branch and to maintain the configs by hand and not to merge any changes.
What are the more elegant options for storing and deploying config files in this sort of set up?
Generally I tried to keep most of these settings in the appSettings (even though I know that's not the "official" right place for them). Then I break the appSettings out into an environment.config file, and have the appSetting element in the web.config reference that through the configSource attribute.
When I setup a new environment, I manually setup the environment.config file for that environment. When, when I deploy a new release, I exclude the environment.config file from teh deployment so that the environment-specific version stays in place.
This lets you deploy new copies of the web.config to include project-related changes, while keeping all of your truly environment-specific settings in a seperate place.
An elegant solution is to use WebDeploy (from Microsoft) for the deployment of your web app. When you run the deployment, you can specify a site specific parameter file which will be used the replace several values in the web.config file.
For deployment, WebDeploy uses a deployment packge, which Visual Studio or msbuild can create.
That way, we have a single deployment package that we can first deploy on a test system, run through several tests and then, when it passes the test, deploy without changes on several servers. Each server has its local parameter file that hardly ever changes and contains the site specific values.
store them on a file server that has the same name in all environments. I am not familiar with all of the configs, but most have ways of doing this. The only problem with this approach is usually dev/local which often share a file server so you have to change the local by hand.
If you actually can't point the configs to a file server, a less elegant solution would be to pull them down via a bat file at deployment or start up. seems like there are alot of options rather than maintaining by hand, that is error prone.

What's the best way to handle web.config file versions in ASP.Net?

I have an ASP.Net web site (ASPX and ASMX pages) with a single web.config file. We have a development version and a production version. Over time, the web.config files for development and production have diverged substantially.
What is the best practice for keeping both versions of web.config in source control (we use Tortoise SVN but I don't think that matters)? It seems like I could add the production web.config file with a name like "web.config.prod", and then when we turnover all the files we would just add the step of deleting the existing web.config and renaming web.config.prod to web.config.
This seems hackish, although I'm sure it would work. Is there not some mechanism for dealing with this built in to Visual Studio? It seems like this would be a common issue, but I haven't found any questions (with answers) about this.
I use nant for my builds. On the SVN I have a web.config.template that contains parameters that are expanded using a properties file. Each environment has its own properties file with different values.
So in short, I don't have the web.config on the SVN, but a template instead.
Something like this
http://www.cptloadtest.com/2007/09/22/Managing-Multiple-Environment-Configurations-Through-NAnt.aspx
NAnt: http://nant.sourceforge.net/
We use the exact method you describe, it works great, for example we have:
web.config (for local development)
web.Dev.config (build server, builds on check-in)
web.QC.config (testing environment)
web.Prod.config (production)
The build script for each environment just deletes the web.config and renames the appropriate one in it's place. Doing this way allows you to easily source control all of them and very quickly do a diff and see what may be different between environments. Updating a config value across the board is much easier as well...the next time it's pushed to that environment, it'll get the new config.
Visual Studio 2010 adds a new feature called XDT Transforms, which automatically combines multiple Web.config files for different configurations.
However, VS2008 does not include any such feature.

Getting Content Files and Primary Output programmatically

For some reason, we have a script that creates batch files to XCOPY our compiled assemblies, config files, and various other files to a network share for our beta testers. We do have an installer, but some don't have the permissions required to run the installer, or they're running over Citrix.
If you vomited all over your desk at the mentions of XCOPY and Citrix, use it as an excuse to go home early. You're welcome.
The code currently has hundreds of lines like:
CreateScripts(basePath, "Client", outputDir, FileType.EXE | FileType.DLL | FileType.XML | FileType.CONFIG);
It used to be worse, with 20 int parameters (one per file type) representing whether or not to copy that file type to the output directory.
These hundreds of lines create upload/download batch files with thousands of XCOPY lines. In our setup projects, we can reference things like "Primary output from Client" and "Content Files from Client". I'd love to be able to do that programmatically from a non-setup project, but I'm at a loss.
Obviously MS does it, either using an API or by parsing the .csproj files. How would I go about doing this? I'm just looking for a way to get a list of files for any of the setup categories, i.e.:
Primary Output
Localized Resources
Content Files
Documentation Files
EDIT:
I have a setup project like Hath suggested, and it's halfway to what I'm looking for. The only problem keeping that from being a perfect solution is that multiple projects depend on the same assemblies being in their own folder, and the setup will only copy the file once.
Example:
Projects Admin, Client, and Server all rely on ExceptionHandler.dll, and Admin and Client both rely on Util.dll, while Server does not. This is what I'm looking for:
Admin
Admin.exe
Admin.exe.config
ExceptionHandler.dll
Util.dll
Client
Client.exe
Client.exe.config
ExceptionHandler.dll
Util.dll
Server
Server.exe
Server.exe.config
ExceptionHandler.dll
Since the referenced assemblies are all the same, what I get is this:
Admin
Admin.exe
Admin.exe.config
ExceptionHandler.dll
Util.dll
Client
Client.exe
Client.exe.config
Server
Server.exe
Server.exe.config
This causes a FileNotFoundException when either Client or Server can't find one of the two DLLs it's expecting.
Is there a setup property I'm missing to make it always copy the output, even if it's duplicated elsewhere in another project's output?
EDIT AGAIN: All referenced DLLs are set to "Copy Local", and always have been. I found a decent article on using NAnt and XSLT to grab the list of files, so that may be a possible solution as well, as neouser99 suggested.
ACCEPTED SOLUTION: I'm pretty much back where I started. All .exe and .dll outputs are put into a "bin" directory in the setup project, loosely packed. The other per-application folders contain shortcuts to the executable in that directory.
The difference now is, I'm going to add a custom action to the installer to use reflection, enumerate the dependencies for each executable output, and copy the .exe and .dll files to the separate directories. Bit of a pain, as I just assumed there was a way to programmatically detect what files would be included via some setup library.
why not use another setup project and just set the 'Package files' setting to As Loose uncompressed files (setup project->properties)? then share the folder.. or something.
edit:
I see, you have 3 folders for your outputs. but the setup project only detects the ExceptionHandler.dll and Util.dll once, so it will just pick the first folder and put it in there.
You could do a setup project for each project - bit annoying maybe..
You could manually add in the dll's to the projects that are missing the assembly's
either by adding in the File by 'add file' or 'add assembly' or 'add project output' if you have those projects in the same solution.. (I doubt that's the case though).
or just dump all of them into one output directory...
Although it's designed as a build tool, you might find NAnt to be extremely useful in what you are talking about. The tasks (build, copy, move, delete, etc.) that you can define allow for very fine-grained file lookups, up to general, full folders. If you also incorporate NAnt into your build process, I think you could find that it helps out in more ways then one.
Another approach that has worked for me in the past is to add the shared resource (Assembly, DLL or project) as a reference to each of the Admin, Server and Client projects. Then open the properties panel for the referenced item in each project and set "Copy Local" to true.
Now when you build the projects, each will have its own instance of the Assembly copied into its output folder.
This should also cause the shared components added in this manner to be replicated in each of the output folders in the setup package.
A completely different approach could be to set them up as symbolic links on the network share. A symbolic link is basically a short-cut where the file-system hides the fact that it is a short-cut, so all other applications actually believes that the file has been copied (http://en.wikipedia.org/wiki/NTFS_symbolic_link).
One advantage of this approach is that the file is updated immediately as the file changes and not only when you build your projects. So when you for instance save one of the config-files with a text-editor the update is applied immediately.
The following MSBuild script part can build your SLN file (you can replace it with .csproj) and will report a list of all projects that were build (Dlls, EXEs).
<MSBuild Projects="MySolution.sln" Targets="Clean; Rebuild" Properties="Configuration=$(BuildMode);">
<Output TaskParameter="TargetOutputs"
ItemName="AssembliesBuilt" />
</MSBuild>
Now, this doesn't really solve your problem, but it gets you a list of everything that was build. You also have copylocal, so you could probably just take AssembiesBuild and copy all DLL and .CONFIG files from there.
Example:
AssembliesBuild = c:\myproj\something1\build.dll
you'd go to c:\myproj\something1\ and simply search for all *.dll and *.config files and include them. You can do this pretty easily with MSBuild or powershell, if you have it installed. To output a XCOPY script from MSBuild, I think you'll need MSBuild contrib projct installed.

Categories