Deploy .Net project automatically with MsBuild and MsDeploy (1)
Q: How to change parameter values in configuration files dynamically
In the first section http://www.cnblogs.com/delexios/p/4933300.html, I mentioned 5 questions regarding auto-deployment in my project. Now I will answer the first question.
For isolating from my project files, I create a new file named VRent.csproj with the root element ‘Project’. All works about auto-deployment are defined in this file.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0" DefaultTargets="BuildConfig"> </Project>
First, I should define some variables on the top of the auto-deployment script file to make sure that these values of variables can be referred in other parts. I have two choices to do it.
- PropertyGroup
- ItemGroup
The meaning of PropertyGroup is like its name. Properties with a custom name and a value can be the child elements of PropertyGroup. So I defined many property groups include the properties regarding application path and name, the properties regarding the path and name of application package, the properties regarding the path and name of application copy and so on. For example
<!-- App path property in IIS--> <PropertyGroup> <IisProxySiteName>\api</IisProxySiteName> <IisDAProxySiteName>\dataAccessProxy</IisDAProxySiteName> <IisUPProxySiteName>\upl</IisUPProxySiteName> <DeployIisAppPathProxy>VRent_Dev$(IisProxySiteName)</DeployIisAppPathProxy> <DeployIisAppPathDAProxy>VRent_Dev$(IisDAProxySiteName)</DeployIisAppPathDAProxy> <DeployIisAppPathUPProxy>VRent_Staging$(IisUPProxySiteName)</DeployIisAppPathUPProxy> </PropertyGroup>
Using $({Property Name}) to refer another value of property has defined before to join with constant values ensures isolation and low coupling to reduce the complication of maintenance.
<DeployIisAppPathUPProxy>VRent_Staging$(IisUPProxySiteName)</DeployIisAppPathUPProxy>
In my project, there are too many properties belonged to one group to manage them. From my side, PropertyGroup is not the best way to use in this case although it is the best practice to store my variables according to Microsoft……
So I chose ItemGroup. Actually, ItemGroup is not used in this way. It is used to group some stuffs because they are similar and have common meta data. Here, I used it to store the variables as meta data of a particular group with a meaningful name. For example
<ItemGroup> <!-- email properties -->
<EmailConfig Include="Email"> <SendMailFrom>test@crm-factory.org</SendMailFrom> <SendMailFromPwd>123</SendMailFromPwd> <SendMailWay>true</SendMailWay> <ServiceCenterEmail1>adam@crm-factory.org</ServiceCenterEmail1> <EmailTemplatePackage>C:\Project\EmailTemplate\</EmailTemplatePackage> </EmailConfig> <!-- union pay properties -->
<UnionPayConfig Include="UnionPay"> <sdksignCertpath>C:\Project\certs\PM_700000000000001_acp.pfx</sdksignCertpath> <sdksignCertpwd>000000</sdksignCertpwd> <sdksignCerttype>PKCS12</sdksignCerttype> <sdkencryptCertpath>C:\Project\certs\encrypt.cer</sdkencryptCertpath> <sdkvalidateCertdir>C:\Project\certs\</sdkvalidateCertdir> <sdkfrontTransUrl>https://101.231.204.80:5000/gateway/api/frontTransReq.do</sdkfrontTransUrl> <sdkbackTransUrl>https://101.231.204.80:5000/gateway/api/backTransReq.do</sdkbackTransUrl> <sdksingleQueryUrl>https://101.231.204.80:5000/gateway/api/queryTrans.do</sdksingleQueryUrl> <sdkfileTransUrl>https://101.231.204.80:5000/gateway/api/fileTransRequest.do</sdkfileTransUrl> <sdkbatTransUrl>https://101.231.204.80:5000/gateway/api/batchTrans.do</sdkbatTransUrl> <sdkcardRequestUrl>https://101.231.204.80:5000/gateway/api/cardTransReq.do</sdkcardRequestUrl> <sdkappRequestUrl>https://101.231.204.80:5000/gateway/api/appTransReq.do</sdkappRequestUrl> </UnionPayConfig> </ItemGroup>
In this example, I defined two items ‘EmailConfig’and ‘UnionPayConfig’.Each of them has its own meta data. For using these values, I can use them with the pattern of %({ItemName.MetaData}) for example %(EmailCofig.SendMailFrom). It follow the Object-Oriented Design so I think using item group is more suitable in concept and semantics in my project.
After I defined all the variables completely. I can use them to change the attributes and parameters in configuration files.
In MS Build technology, one Task element which is the child element of Target represents a job run by MS Build. I need a special task which support modifying .Net configuration file that is a actual XML file. I found one named XmlPoke can be used. For example
<XmlPoke XmlInputPath="$(ProjectPathDAProxy)Web.config" Query="//VRentEmail/host/@address" Value="%(EmailConfig.SendMailHost)"> </XmlPoke>
I refer the value of ProjectPathDAProxy I defined in one property group as the value of XmlInputPath which represents the physical path of a configuration file. I used XPath to find the attribute I would like to change and refer the value of EmailConfig.SendMailHost in one item as the value used to change the attribute. I wrote down all the attributes and parameters I would like to change and each of them has a related XmlPoke task.
Finally, I use a target as the container of all the XmlPoke tasks.
<Target Name="BuildConfig"> <XmlPoke XmlInputPath="$(ProjectPathProxy)Web.config" Query="//client/endpoint[@name='BasicHttpBinding_IDataService']/@address" Value="%(ServiceConfig.dataServiceAddress)"> </XmlPoke> </Target>
If I use VRent.csproj as parameter to MS Build, it works. everything goes well.