Visual Studio : How to switch between test / production databases quickly? - visual-studio

I'm working in a solution which includes a windows service host project that uses a single app.config file which contains everything the service needs (logging configuration, WCF configuration, custom configuration, and, connection strings).
The way I actually work is when a user complains about something wrong in the production environnement, I edit the app.config file, modify the connection string so it points to the production database, recompile the service host project, then run the application in my dev environnment to see what's going on.
If I have to test things that would be too risky for the production environment, I edit again the app.config file, modify the app.config file so it points to the test database, recompile the service host project, ... you see where I'm going ...
To avoid the burden of editing the app.config file everytime I have to switch environments, I decided to create a "Production" build configuration and a "Test" build configuration. I added two additionnal config files, one for each environment, which are replicas of the main app.config file except that their connection string points to their respective database. I modified the pre-build event of the project to include code that copies the environment's app.config file depending of the selected build configuration.
I have two concerns about that method :
If I have anything else to modify in the app.config file (WCF, logging, etc.) I have to remember to replicate my modification in the other file. (Big problem for me as I have as much memory as a red fish)
I hate making the project more complex to work with because of the additional build events, additional files in the project directory, etc.
Each build configuration outputs in a different directory. I hate having duplicates of the same code just to overcome that data source issue.
Anybody can suggest a simpler way to work with multiple environments ?
Thanks in advance.

Related

Azure Pipeline File Transformation is not working. Why?

I'm still trying to create my first Azure Pipeline CI / CD. My CI part is working fine, my CD is also working except I cannot apply my Web.config file transformations.
Let me first show you what I have then I will ask several questions below. The build with generated artifact. I also copy manually my 3 config files.
Wen I open my WebAPI.zip file here is the path and content:
Here is my pipeline project
And the details of my staging phase:
When I run this full pipeline my config file is never transformed but I get no error. I just get a
2019-05-02T03:27:23.5778958Z ##[warning]Unable to apply transformation
for the given package.
I also have the debug log with full information but it doesn't give me much information for now. I will add it here later.
Questions
Azure Pipeline File Transformation is not working. Why?
Is it because the File Tranform task only look for config file in zip?
Is this system then just ignoring my tranformation file in root of artifact?
So I think my manual copy of config transformation file is obsolete?
How can I then add my transformation file into my zip?
In my csproj I already set all my tranformation files on Build action content, copy always, this is ignored too, is it normal?
EDIT 1
One more important question: Is it possible to simply ask the deployment system to ignore or not deploy my config file. It is not something I want to deploy every time. I like the idea I have to do it manually or from alternative deployment system. With this solution I can have some other issues if I save a version or build variable in my config file. Then is it possible to modify a already deployed file after deployment? I'm looking for workaround here. Example: I read a value in my existing config file then I increment this value by one or simply replace this value with another?
EDIT 2
I'm now able to add the config file to the WebApi.zip package on root and/or in bin folder. I followed the comment of Shayki Abramczyk bu using the xml transform of deploy. Still not working. And the errors messages are so poor. Seriously Microsoft? Is your transformation system even working? I see question similar to mine everywhere.
And now I get
The file is correct, transform works fine from Visual Studio Publish tool. I really think the xml transform tool from Microsoft in Azure is just not working.
EDIT 3
Is it possible to issues from my transformmations come from NLog because of the name and then special rule I apply on it?

Property values replacement in configuration file before MSI is being packaged

I have a Windows.Forms client that is packaged as MSI by using a Visual Studio Deployment Project.
My app.config has some configuration properties whose values must be replaced by the correct ones depending on the environment I want to deploy the client into.
For instance, my client do connect to a set of COM+ services that are behind a WCF facade, so I have some URLs in the configuration file that vary depending on the environment (development, integration, etc etc).
In such way one can find in the application config line like this:
<add ServiceName="MyService" ServiceEndpoint="$(WS_URL)/MyService.svc" MaxMessageSize="xxxxxx"></add>
Well, the thing is that I need to execute a batch file (.bat) to load some variables and then replace the variables in the app.config, but, I need to do the replacements in the application configuration file that is being packaged in the MSI, and not perform the replacement in the "original" configuration file that is in the client project.
In fact what I would need is just to get the path, of the application configuration file, that VS is about to package, and pass the file-path to my script so that it does the replacements.
NOTE: In the above sample line $(WS_URL) is the variable that must be replaced by its correct value depending on the deployment environment configuration.
I would create 2 copies of your App.Config in source control and associate one with your project for F5 builds / dev debugging and another one that gets consumed by the installer for production use.
Finally I have the solution that fit our needs. My need was mainly to just have one unique configuration file for the Windows.Forms client and being able to replace some property values in it, just before the file is packaged in the MSI.
I thought the binaries that are packaged within the MSI were taken from the project(s) output dir., but they are not, so I couldn't use that location to execute our "variable replacer" script and get the final App.config file ready to be packaged.
We a have a .bat file, one for each kind of environment configuration, in which we centralize the configuration properties applying for Windows.Forms, Web-Applications, COM+ Serviced Components, so I was disgusted with the idea of replicating the configuration file of the client, because my aim is also to reduce the number of configuration files, to reduce the risk of making a mistake, while keeping the process of creating/maintaining build environments easy.
I couldn't find any doc to tell me how could I get the path, of the temporal folder or whatever, where the files are, just before the MSI is being packaged. If I would have access to it, then I would have executed our "variable replacer" script pointing to that directory and problem solved.
My workaround was to place a customized pre-build event, so that the I copy the "template" App.config to the project directory, and once it is there, I run the script to replace the property values.
Now, every time the deployment project is built, we are sure it contains a valid configuration file.
Just FYI, here is how the pre-build event looks like:
XCOPY /Y $(ProjectDir)config\*.* $(ProjectDir)
CALL ..\ScriptsCentral\do_apply_config.bat $(ProjectDir)App.config etc
EXIT 0
NOTE: I had to put the EXIT 0 explicitly because we build all the projects with msbuild and devenv.com and I got the build process stopped in the part where it executes the build event.
(thanks #ChristopherPainter for your time and comments. +1 for your proposal)

How do I handle multiple web.config transforms for different instances when dealing with multiple publish targets?

I have an Asp.NET MVC site that I manage multiple instances of. Each instance uses it's own database but the code base is all the same. To facilitate this I have several build configurations with matching web.config transforms, so that when I publish it doesn't use my development database but instead uses the specific database for that site instance.
The problem with this came today when I went to publish an update to one of the sites. I forgot to change the build configuration, so my publish to site A was using a web.config transform that was meant for site B, and mayhem and confusion ensued.
Is there any way to to specify that a specific publish target will ONLY be used with a specific build configuration?
Or is there a better way to handle this situation than juggling build configurations?
One way to deal with this sort of thing, and I'm not certain it's the best, but it is a way, is to set certain configuration values in a higher level web.config or machine.config file that always resides on the machine in question.
Then just make sure that your project files don't override those configuration values.
Here are some considerations if you do this.
If you want to source control these values, it can be more difficult
this way (this could be a pro or a con depending on your
environment).
If other virtual sites are on the same machine and use the same
configuration values, this could affect them all, and if multiple
sites do use that same configuration value, changing it at the
source will change them all (again, could be a pro or a con
depending).
If something is wrong with the value, it can be harder to
determine where the problem is or what is causing it.
Getting to machine.config may be difficult in your organization
or with your hosting provider depending on your access/security
privileges, and it's not always possible to put a web.config at a
higher level than your application.
Obviously the good thing here is that you can have a different value configured on each machine and as long as these values are not also set in your web.config (which would probably result in an error), you won't have to worry about compiling different versions.
I believe that Visual Studio 2010 has a way for setting different config files for different build types, but that sounds pretty much like what you are already doing, so forgetting to build the right way can still end up with similar results.
You could attempt to set up continuous integration with something like TFS Build if that is available to you, in which case what gets built for prod could be set up to always work a certain way and always pull from the correct build type.
Hope something here helps.
Maybe you could go a solution where you don't rely on the 'Publish' dialog of the web application that requires you to make the right setting every time, but instead use a automated command-line like solution (batch file, your own msbuild target, or a build server like CStroliaDavis suggested [cruisecontrol, tfs, teamcity]).
You can just call the 'package' target from command line which creates a package:
msbuild MyWebProject.csproj /t:Package /P:Configuration=Release;DeployIisAppPath="Default Web Site/Main/MyWebProject";PackageLocation="F:\MyWebProjectDeploy.zip"
This also creates a *.cmd file so you can deploy it like this:
F:\MyWebProjectDeploy.deploy.cmd /Y -allowUntrusted /M:http://webserver/MSDeployAgentService /U:Administrator /P:"Secret"
You can add a custom *.msbuild file to your solution that performs these actions, or maybe it's easiest to just add a command to Tools -> External tools.
With kwateeSDCM you can not just deploy apps and web applications but you can also manage instance-by-instance parameters or file overrides. I've only used it with tomcat wars but it's not tied to a language or a platform so I suppose it should be straightforward to configure it to work with ASP.NET as well.

Visual Studio local project setting best-practices?

How do people commonly store local .settings files for their projects? For example, I have a solution for a web project in Mercurial. I have a data project containing my entities and repositories. My connection string is stored in Settings.settings and I'd like to have different sources depending on my location.
I was thinking I could simply move the file to Settings.settings.global and requiring anyone to change it when they clone my repo. Is there a better way of going about this? What are the best-practices for handling such things in Visual Studio?
One concern of mine with simply renaming the Settings.settings file containing my data source is that Visual Studio seems to automagically modify my app.config with the new values and I'm not sure how that will be handled if I force people to rename.
I'm not clear on whether your organization is using revision control or not, but generally speaking, the .settings file committed to your revision control server contains some generic settings (or more specifically, testing or production settings). Then, each developer simply checks out the project, modifies .settings freely to suit their local configuration, and never submits the changes back to the revision control server. Everybody's happy!
Not sure about .settings files, but for .config files and any other projects I'm using a file like app.config.sample which is included in the repository, along with a .cmd script which is creating the app.config file on run.
After cloning and running the .cmd script, any developer can customize the app.config as needed.
Off-topic: everyone I've asked advised me to keep the connection strings in app.config/web.config, but YMMV.
Some links:
ConnectionStrings Property
What is the best place to keep the Connection String

Best way to configure build directory structure for a windows application

I am writing a small application at the moment and am trying to organise my build output to be a little closer to the finished product. The application is made up of a number of different projects. There is a core library that contains most of the functionality, a GUI app and a command line app that both reference the Core Dll, and a number of Plugin Dlls that are loaded at runtime and implement different data sources, these all reference core.dll, these also may include some other third party dlls. There are also a number of peripheral files such as a readme. And finally the core.dll and the datasource plugins are unit tested.
I would like to configure my build so that everything is output into directories as I would expect it to be when installed. I want debug and release builds to be built into different directories but otherwise have the same directory structure. I only want tests to be built for debug builds, and want them to be runnable, but seperated (I guess all test dlls would get output into a seperate directory). Here is how I imagine the structure will be.
Code/
solutions etc here
Debug/
Project.Core.dll
Project.Gui.exe
Project.Cli.exe
readme.txt
lib/
ThirdParty1.dll
ThirdParty2.dll
DataSource/
DataSource1.dll
DataSource2.dll
Tests/
Project.Core.Tests.dll
DataSource1.Tests.dll
Release/
same as Debug but without tests.
Is there any way of getting a solution to build like this? I'm beginning to think it will be difficult to build the plugins and the app all from one solution, and probably not even wise, but as they will all be distributed together it would be nice. I am open to using Nant or another build tool if that will make it simpler.
It is possible. Just modify OutputPath tag manually in each .csproj in both Debug and Release file to something like this
<OutputPath>..\$(Configuration)\any_subdirs</OutputPath>
You can disable tests building for Release using Configuration manager.
Modifying each project every time you create a new one is annoying.
Here's the solution:
Locate the real vs project, it'll be somewhere under ("%programfiles(x86)%\Microsoft Visual Studio 10.0\Common7\IDE\ProjectTemplates*")
Copy it locally somewhere.
Extract it.
Edit the contents making changes that better suit your project layout style. Make sure you update the project name, the name is what you see when looking for the project in the new project dialogue box. It's xml tag is Name, you'll find it in the {something}.vstemplate file.
Compress the content again. (Note: the contents must NOT be in a sub folder, so /* and NOT /{somefolder}/*).
Place your custom project under ("%USERPROFILE%\Documents\Visual Studio 2010\Templates\ProjectTemplates*").
Add a new project is Visual Studio, selecting your custom one, and enjoy!

Resources