Before I dive in more let me clarify that if you are using VS 2010 then in common scenarios you may not even need to do custom parameterization, coz VS 2010 already parameterizes things like IIS Application Name, Application physical installation directory and connectionStrings… So when you actually create a web deploy .zip package you can easily build it once and deploy it several number of times by changing the parameters values…

Custom Parameterization

The typical scenarios where you will need to do custom parameterization is for scenarios like:

You have an appSetting which needs to be changed by server admin at install time…

You are using a WCF Service and you want to change the end point at install time…

You have created re-usable web package for community apps and have bunch of questions to ask the users before they install the app (similar to all of the apps that you find in Application Gallery eg ScrewturnWiki, DNN, etc…)

Scenario

In today’s post I am going to use Parameterization with VS 2010 for changing an appSetting & WCF Service end point… Before we do that let us look at the web.config settings which we want to change at install time…

App Settings - The Log Folder location here (“value” attribute) is something which I want my admin to be able to change at production install time to a shared location so that if my app is virtualized and put on a web farm then I have a common place to go and look at the log…

WCF Endpoint – Below is my WCF EndPoint URL (“address” attribute) which I would like my admin to change to the servers/sites on which the WCF Services will get deployed…

We want to make sure that no matter which direction our IT Admin takes he/she gets an opportunity to provide values for the above two parameters…

Parameters.xml File format

As I explained in the earlier post Parameters.xml file can be passed to Web Deploy when your .zip Web package is being created and that allows Web Deploy to determine what items in your web should it mark as “changeable” at install time… VS 2010 makes your life easier by allowing you to simply drop the Parameters file in the root of your web project and if a file with the name Parameters.xml is found in the root of your project it passes it to Web Deploy which then parameterizes your web…

The Parameters.xml file follows a specific format, the key attributes to note for each parameter that you declare within parameters.xml file are:

kind – There are several kinds of parameters but the key ones to remember are:

XmlFile – Use this for web.config, any settings XML files etc where you can make replacements using XPath

TextFile – Use this for non-XML file where you can make replacements by looking for fixed text or token within a file. e.g. you can put @@replaceme@@ in the a settings.ini file and during installation that text can be replaced

match - This depends upon the parameter kind… For e.g. for XmlFile parameter the match expression would be a XPath… For TextFile the match expression could be @@replaceme@@ which you might pre-place in the file…

Declaring Parameters using Parameters.xml

Below is the content of Parameters.xml file that I dropped to the root of my MVC Application

If you notice each of the Parameter above you can see that I am using XmlFile parameter kind with Xpath as the match syntax… After adding this Parameters.xml file into my project my solution explorer looks as below:

Now I can simply right click on my MvcApplication and hit “Build Deployment Package”… The resultant .zip file should be created at obj\Debug\Package\MvcApplication1.zip…

Validating that Parameters really worked

Now to validate whether the parameters really worked you can very quickly open IIS Manager (Start –> Run –> InetMgr) and select your Default Web Site

You can now click the “Import Application” command on the right side bar and pass the newly created .zip package to it.

On Hitting next on the Import Application wizard you will be able to see the “Parameterization” screen which user will be able to pass values to the parameters. Notice even our defaultValues provided in the Parameters.xml show up:

I am now changing the value of these variables as shown below:

When I now go ahead and finish the wizard by clicking “Next” and go ahead and inspect the Web.Config file in the deployed location, I can see that the changed parameter values were applied to the web.config file seamlessly…

Also do note that in the process above “Parameters.xml” will also get deployed with your web application, in reality you do not need that file… To avoid that file from getting deployed you can go to its properties (select the file and hit F4) and set “Build Action” = None as shown below:

You can set MSBuild property ProjectParametersXMLFile and provide different parameters.xml per build configuration... That way the correct Parameters.xml file will get picked up when you create a debug vs release build...

You can set this property by hand editing your project file or even passing it from command line...

Is there any way to parameterize the actual deploy contents (not the web.config) after a deployment package is created? In other words, we would like our build process to create a single deployment package, from which we can install multiple customized customer applications. Simply put, the only thing that differentiates each customer application (aside from the web.config, which your article on parameterization handles perfectly) is a single resource folder (the folder contains a couple of customer specific images). I realize that our actual install/deploy application could bind the resource folder to a generic build, thus creating a customer specific deployment package before calling the web deploy api; however, I would like, if at all possible, to initially limit the scope of my deployment application, thus relying on our original build artifacts.

I do not think there is an easy way to do this although do drop me an email and I will connect you with my team and you can perhaps have an indept conversation... After that do update the results of the conversation here for others to benefit from...

Q. Re: nhibernate.configA. The other day I too faced a similar problem not with nHibernate.config but with something else... Can you possibly send the config file and the exact parameters you are using to Vishal.Joshi@Microsoft.com. We will try to see if we can reproduce the issue locally.ThanksVishal

Q.RE: nhibernate.configA. Owais on our team investigated this and as nhibernate.config contains namespace declaration at the top (I guess you have the same) then the XPath used should be namespace agnostic. For instance the XPath for connectionString would look something like

We're doing automated deployments from VS 2010 using WMSvc to our testing environment, and are preparing to do our first deployments to production. We would like to use an existing package (from the most recent drop folder) to deploy to production, but want to utilize our release config transform. We do not want to re-run the build since there are changesets that have been checked in since the last deployment that are not ready for production. What's the best way to accomplish this?

We would rather not manage the parameters in two places (config transforms and parameters.xml) since we have already defined the necessary values in our web.release.config, and don't have a separate server admin role on our team that needs the ability to set config values on the fly at install time.

Any suggestions you can offer would be greatly appreciated. I would think this is a common deployment scenario, but am not seeing how it can be accomplished.

Q. We do not want to re-run the build since there are changesets that have been checked in since the last deployment that are not ready for production. What's the best way to accomplish this? A. Dan, when you create a package to your existing drop location doesn't web.config transform & parameters.xml already work at that time. If yes then wouldn't the right web.config already exist?Are you aware about SetParameters.xml file which gets generated. Usually you can run the package with a new SetParameters.xml and that would set the new value even if the package does not contain the correct value.The scenario feels very specific if you would like to drop me an email at Vishal.Joshi@Microsoft.com or call me at 435-705-2031 then I will be happy to dive into details and we can come up with a design recommendation.ThanksVishal

No offense, but for simple cases it would be nice to just use web.config transforms for connectionStrings... now I have to use a separate file just to set that value. Is there a way to do that without using Parameters.xml?

btw, I'm publishing the project using WebDeploy via MSBuild. It's all automatic and I do not go through the IIS gui to import the package.

Q: Jim asked: No offense, but for simple cases it would be nice to just use web.config transforms for connectionStrings... now I have to use a separate file just to set that value. Is there a way to do that without using Parameters.xml?A. Jim, if you are publishing directly to the server via Web Deploy and MsBuild and you just want to set connectionString values you should be to do those using Web.Config transforms. You just need web.configuration.config and from team build just publish that configuration. The steps are explained at http://vishaljoshi.blogspot.com/2010/11/team-build-web-deployment-web-deploy-vs.html. In your case I do not think you need parameters.xml unless I am mis understanding.thanksVishal

I've double checked things and I'm still getting connectionStrings with "$(ReplacableToken_Review-Web.config Connection String_0)" in them instead of the value in web.Review.config or just the default value in web.config. Any hints/suggestions?

Jim, are you trying to package your application as a .zip file or actually publishing to the web server directly? Can you share the msbuild commandline you are using? ideally you should have /t:MSDeployPublish and not /t:Package. The package is an intermediate destination which has the tokens in it. Publishing already replaces the token.If you are intentionally creating the .zip package then there is a setParameters.xml file which is created with the package. Do you see your final values in it?thanksVishal

Hi Jim, thanks for the response. Are you suggesting that your deployed web.config contains the token or the one in .zip file contains the token? If it is later than it is expected as SetParameters.xml and deploy.cmd file will have the correct values. If the deployed web.config on the server has tokens then there is certainly something wrong.Can you try removing /p:CreatePackageOnPublish and try if your deployed web.config has the tokens.ThanksVishal

Yep, the deployed web.config contains the token. Removing CreatePackageOnPublish didn't help, unfortunately. Any other ideas? Otherwise, maybe we can work this out via email tomorrow and I could share my screen so you can see more details. jim@biacreations.com if you're interested

Hi Jim, I am responding here so that in case anyone else lands up into anything similar then we would have a trail. But in anycase let us give it one more try. As I understand you do not care about parameters and are not really using them in anyway. Rather you have all your transforms already set in web.configuration.config file. If that is the case then you can pass /p:DisableAllVSGeneratedMSDeployParameter=False from MsBuild, that should turn off all the tokenizations. I am sorry you have to use these, these properties were just meant to be backups in case something did not work out of the box. Btw, if you get a chance can you try your scenario with File--> New Project instead of your existing project, I have not seen this issue before on my machine so am still curious what might be going wrong.ThanksVishal

Thanks for your help Vishal. Adding that flag still didn't fix the problem. I'm going to recreate the solution/project files and see if that helps things. This was an mvc2 project upgraded to mvc3. I'll let you know if the new solution has the same issues.

Good news, sort of :) Recreating the solution and project files solved my mystery. I no longer get tokens showing up in the deployed web.config. Vishal, thank you for your help with this and if you would like a copy of the files for analysis, please let me know.

Is there a way to fix the order of parameters ? I.e. I'd like to have "host1", "port1","suffix1", "host2" and etc. But VS breaks the order and it becomes "host1" "suffix1" "suffix2" ... and in the end "host2"

Hi Mad, Yes the priority of the parameters generated can be controlled. It is defined by following msbuild properties which can be changed in your project file.

The default setting is *************************************************************** Global setting on MSDeployParameterPriority to change the Parameter order show up in inetmgr UI The lower the number, the earlier it show up in the Inetmgr UI (-100, -80, -70, ....60, 100) Default priority is 0. Any integer number is allowed. *************************************************************** &ltPropertyGroup&gt &ltVsIisAppParametersPriority Condition="'$(VsIisAppParametersPriority)'==''"&gt-100&lt/VsIisAppParametersPriority&gt &ltVsContentPathParametersPriority Condition="'$(VsContentPathParametersPriority)'==''"&gt-80&lt/VsContentPathParametersPriority&gt &ltVsDestinationVDirParametersPriority Condition="'$(VsDestinationVDirParametersPriority)'==''"&gt-70&lt/VsDestinationVDirParametersPriority&gt &ltVsSetAclPriority Condition="'$(VsSetAclPriority)'==''"&gt-60&lt/VsSetAclPriority&gt &ltUserParametersFileParametersPriority Condition="'$(UserParametersFileParametersPriority)'==''"&gt-50&lt/UserParametersFileParametersPriority&gt &ltUserWebConfigParametersPriority Condition="'$(UserWebConfigParametersPriority)'==''"&gt-40&lt/UserWebConfigParametersPriority&gt &ltVsSQLDatabaseScriptParametersPriority Condition="'$(VsSQLDatabaseScriptParametersPriority)'==''"&gt60&lt/VsSQLDatabaseScriptParametersPriority&gt &ltVsWebConfigAutoCsParametersPriority Condition="'$(VsWebConfigAutoCsParametersPriority)'==''"&gt100&lt/VsWebConfigAutoCsParametersPriority&gt &lt/PropertyGroup&gt

There is an Item collection called MsDeployDeclareParameters which when outputed can give you the priorities which is taken by default.

If you have more questions do not hesitate to write back at Vishal.Joshi@Microsoft.com

I have been struggling to get this working for settings in the web.config file that are contained in the APPNAME.My.Settings section of the web.config file.

I have noticed that all the examples given are modifying an attribute, rather than an element (which it would need to do in this case), and wondered if this is a limitation of this functionality.

I believe my xpath syntax to be correct (match="/configuration/applicationSettings/MYAPP.My.MySettings/setting[@name='MYSETTING']/value", where MYAPP and MYSETTING correctly match the values in the file).

Hey Mark,There was a missing quote in my previous comment. Fixing the typo and resending.

Below is a note from Owais from our team, hope that helps :-)It might be because the file is using namespaces. You can check at the top of the file if that is the case. In case it is then change the xpath to be namespace agnostic.//*[local-name()='setting’][@name='MYSETTING']/*[local-name()='value']

This xpath should work regardless of whether a namespace is being used. Make sure the case in the xpath matches the case in the file, since this is case senstive.ThanksVishal

There was no namespace in my file, but using the ns agnostic syntax, with the addition of '/text()' I have now got this to match correctly, as shown here;match="//*[local-name()='setting'][@name='MYSETTING']/*[local-name()='value']/text()"

It seems that it was my incomplete knowledge of xpath syntax that caused my problems, so apologies for moving away from the original topic of this article.

Great post, it has helped me a lot to streamline our release procedures.

Is there a way to declare some kind of validation on the input fields (regular expression)? Or is it possible to declare a fixed set of values that can be entered in the field. For example, if you have an appsetting "LogMethod", then a combobox appears for this field (rather than a textfield) with the values Information, Warning and Error.

We are using config transforms extensively. However we are facing 1 issue. We are using SIT (Test) package for deployment in test environment and it has web.config generated by a config transform. Now for moving to UAT we will use signed off SIT package, but config file needs to be changed. And we dont want to queue one more build for UAT config. Wa are exploring different ways of doing this using single build. Parameterization doesn't look to be working in this case.

I have question similar to paul van bladel. Is it possible to remove a XmlNode, rather than updating the values via parameters.xml?

In our case we're creating deployment package after successful integration tests and we're using same package to deploy to all environments. We change environment specific properties at deployment time by manipulating SetParameters.xml.

Hi Gurmit, You will have to write a custom transform to accomplish this. You can read more on Sayed's blog at http://sedodream.com/2010/09/09/ExtendingXMLWebconfigConfigTransformation.aspx Btw, if you get to writing your custom transform can you put it in some open source location so that the rest of the community can benefit from it as well.ThanksVishal

Thanks for this interesting post. I have one question though:Is it possible somehow, to keep the values of the deployment parameters across an update installation.As it is now, when an update needs to be run, every parameter has to be entered again, the default values being the ones from the paramters.xml used when generatiing the deployment package.It would be much easier, when the default values would be the ones entered during the previous installation. Is this possible somehow? There is the same question at http://stackoverflow.com/questions/16450553 but unfortunately it has not been answered.Thanks in advance, Stefan

HiI have parameters.xml in my web project. When I publish the project, Setparameters.xml is getting generated as per the parameters.xml.The problem is, I used TFS build to generate package (using the parameters "DeployOnBuild=true;DeployTarget=MSDeployPublish;CreatePackageOnPublish=True;MSDeployPublishMethod=RemoteAgent;MSDeployServiceUrl=http://{myserver}/msdeployagentservice;UserName={username};Password={password};DefaultPackageFileName=PKG.zip"). The parameters.xml is not the same parameters.xml that I included in the project location, and SetParameters.xml is generating from that parameters.xml. Do you have any idea why TFS build is unable to pick the parameters.xml that I have included in project folder.