I'm using SlowCheetah for XML transforming a bunch of config files in a project.
However, this same solution is part of a load balanced setup, where some config values differ between the different servers (two, in this case).
I have the following build configs
Debug
Release
Release.Test
Release.Prod1
Release.Prod2
Almost everything in Release.Prod1 and Release.Prod2 is identical, except for some values in one of the config files. Is there any way I can have a file like Something.Release.Prod.Config to be used on both of these build configs instead of having two identical files (Something.Release.Prod1.Config and Something.Release.Prod2.Config)?
...and to elaborate: In this case I am deploying to two environments, so one duplicated file is not really a huge crisis. What if you have ten or a hundred servers? I see no reason why a setup with a CI-server (Specifically TeamCity in this case) should not be able to do this, even though I suppose more customized setups are common in such environments.
How is this usually handled?
I suppose I can do some magic copying of files back and forth as a build step before the actual transformation happens, but this seems like a messy and overly complicated solution.
The configuration transformations are handled by the $(Configuration) variable in the TransformsFiles.targets file.
<TransformXml Source="#(_FilesToTransformNotAppConfig->'%(FullPath)')"
Transform="%(RelativeDir)%(Filename).$(Configuration)%(Extension)"
Destination="#(_FilesToTransformNotAppConfig->'$(OutDir)%(RelativeDir)%(Filename)%(Extension)')"
Condition=" Exists('%(RelativeDir)%(Filename).$(Configuration)%(Extension)') " />
Here, you can change $(Configuration) to be any other value, like "Environment". Then just set the "Environment" variable in your MSBuild args -
/p:Environment=Prod
This should allow you to keep your build settings and do your transforms independently.
Related
I am looking for a hopefully ready, out of the box solution for my problem here. Here is outline:
I would like to have a file named local.config that contains certain information about my local environment.
That file will be ignored and will never make its way to the build server (ignored from gitHub).
Whenever I build locally, transformation happen.
Whenever I build on the server, whatever information found in main app.config is used.
Both SlowCheeta and Configuration Transform should work for your needs.
Here is what I ended up doing and there is probably better ways to do what I was after but unfortunately (and the fault is on me for not formulating the question correctly).
Modify the cproj file with the following:
<UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v10.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
Place your config files and transforms into your project accordingly. Every time you build, the configuration is transformed just fine.
I did not like that fact I had to have an extra base.config file but apparently, transforming from source directly to the target makes the msbuild rather upset.
We are in the process of trying to automate our build/deploy processes with the Release Management tool for Visual Studio (formerly InCycle).
The Release Management tool includes a facility to modify settings in a web.config (or app.config). However, there are situations where I'd like to be able to do more than this.
For example, we have URL rewriter rules to automatically redirect HTTP requests to HTTPS. But this won't work (at present) on our dev workstations. So, the "base" version of the web.config doesn't include the rewriter rules -- they are inserted at build/publish time via a web.config transform.
But the Release Management "configuration variable" mechanism won't let me specify more than a single line as a replacement value.
I realize I can remove line breaks, and condense an XML fragment to a single line of text. But I'd rather not have a web.config with lines that are several thousand characters long. And I suspect our IT folks -- who after all may also need to view/edit the file -- would feel rather more strongly about this than I do ;)
In general, the web.config transform mechanism had several modes: you could change a setting but also insert or replace (or delete) an entire section / XML element. While it's nice to no longer be restricted to web.config files (out of the box), the new functionality seems to be much more limited.
Am I missing something? Has anyone else found this to be an issue? What did you do to work around it?
You can still use xml transform to achieve what you want. Make sure that your transform are applied during your build, and the resulting web.config file available in your build output folder will be containing your URL rewriter rules. RM will pick it up from there and apply any other normal token replacement.
Here is a post that help in this regards: http://incyclesoftware.zendesk.com/entries/21487316-InRelease-with-Web-Deploy
If you have multiple stages in your release path, and for example the first stage should not have your URL rewriter section, than it may be a bit harder. You will need to apply your transform as part of your deployment. Multiple components/actions will need to be used for that (xcopy component, xml transform action/component).
I can't find it now, but I know there is some command line tool you can invoke to achieve your xml transformation as part of your deployment.
Apologies for my lack of knowledge about rewriter rules but can they exist in the base version of web.config and be set up so that they don't effectively do anything and 'rewrite' to HTTP?
If that's possible then the way I would do this is to configure a web.config.release file that will create a tokenised web.config via the transformation process. However, rather than use Web One Click Publish I use the /p:UseWPP_CopyWebApplication=true /p:PipelineDependsOnBuild=false arguments in the TFS build definition to apply the transformation. This then results in a build in the drops folder that is completely unaware about any environment it will be deployed to. You then simply use an XCopy Deployer-based component in RM to deploy the website and replace all the tokenised values for that environment. See my blog post here for more details of the technique.
I have created three different solutions for three different clients, but those solutions are for an app that have the same features, classes, methods, resolution, except for the images, XML resource files, and a web service reference, that are specific for each one.
I would like to have just one solution for all those apps, that I could open in VS2010 IDE for edition, without errors. So, when I need to build or publish an specific app, I just set the client which one I need to, and go ahead to building or publishing.
It is important to consider that XML file names will be the same, as classes and images names too. The difference will be the content, but the name will always be the same.
My intention is to reduce my effort to maintain many solutions, having just one solution to work with.
In my company, we will have more than those three clients soon, so I am worried about how to maintain that. The best way will be have just one solution and when I need to generate a new app for a new client, I have just to change/include a few things (like some resources and images) and compile to a new client folder.
Is it possible? If so how?
One option would be to have a master solution which had the following
A "Template" project that contained your actual application and all of the shared code
Projects for all of your clients
In the projects for your clients, you could have links to the files in your files that come from your shared project. Then, in each of those projects, you could add the files that are only specific to them.
With this kind of structure, whenever you made a change to your Template project, all of the client projects would be updated as well because they just have pointers back to the Template project.
A good reference for this kind of setup would be the Json.Net Code Base. There he has a solution and project for all of the different configurations, but they all share the same files.
In terms of ensuring that the xml files are named properly, you might just want to put some checks into your main application to ensure that it has all of the files needed or potentially add a check into your build process.
There are many ways you could look to tackle this.
My favorite would be to run some sort of pre-build step - probably outside of Visual Studio - which simply replaces the files with the correct ones before you do a build. This would be easy to automate and easy to scale.
If you are going to be building for many more than three customers, then I think you should look to switch from Visual Studio building to some other automated build system - e.g. MSBuild from the command line or from something like TeamCity or CruiseControl. You'll find it much easier to scale if your build is automated (and robust)
If you don't like the file idea, then there are plenty of other things you could try:
You could try doing a similar step to above, but could do it inside VS using a pre-Build step.
You could use Conditional nodes within the .csproj file to switch files via a project configuration
You could look to shift the client-specific resources into another assembly - and then use GetResourceStream (or similar) at runtime to extract the resources.
But none of these feel as nice to me!
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.
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.