MSDeploy setParameter not working - xpath

We are trying to integrate a 'build once, deploy anywhere' model in our build-deploy system.
MSDeploy works wonders for this, cutting down build time dramatically with CRC checksum comparisons and (for the most part) it works just as well when using parameterisation to change applications web.configs depending on the environment we deploy to.
I have the majority of these parameters nailed down, but a few elements and attributes never seem to change, no matter how many different ways I call them in the parameters.xml file. I have outlined three examples of this, here is the web.config file I am trying to change:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="DbConnectionString" connectionString="Data Source=null;Initial Catalog=null;Trusted_Connection=no;User ID=user1;Password=pass*9;" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<customErrors mode="On" defaultRedirect="/Library/Error/PageNotFound.aspx">
</customErrors>
</system.web>
<applicationSettings>
<settings>
<setting name="service_Address" serializeAs="String">
<value></value>
</setting>
<settings>
</applicationSettings>
</configuration>
Here is the parameters.xml file:
<parameter name="DbConnectionString" defaultValue="">
<parameterEntry kind="XmlFile" scope="\\web.config$" match="/configuration/connectionStrings/add[#name='DbConnectionString']/#connectionString" />
</parameter>
<parameter name="customErrorsMode" defaultValue="">
<parameterEntry kind="XmlFile" scope="\\web.config$" match="configuration/system.web/customErrors/#mode" />
</parameter>
<parameter name="service_Address" defaultValue="">
<parameterEntry kind="XmlFile" scope="\\web.config$" match="/configuration/applicationSettings/aim.Web.Properties.Settings/setting[#name='service_Address']/value" />
</parameter>
And here is the corresponding setParameters.xml file:
<setParameter name="DbConnectionString" value="Data Source=dbserver;Initial Catalog=DB1;Trusted_Connection=no;User ID=user1;Password=pass*9;"/>
<setParameter name="customErrorsMode" value="Off"/>
<setParameter name="service_Address" value="https://myservice.asmx"/>
I have tested each XPath expression and the results are the exact same as any of the other working parameters, but the above never seem to change.
Does anyone see anything obvious I'm missing here?

service_Address
I found the answer to this problem here:
Replace web.config elements with MSDeploy
I was missing 'text()' at the end of the XPath expression, the correct XPath is:
/configuration/applicationSettings/aim.Web.Properties.Settings/setting[#name='ai‌​m_Web_AddressService_Address']/value/text()
customErrorsMode
For the customErrorsMode problem, I was missing a '/' at the start of my XPath expression. The correct expression is:
/configuration/system.web/customErrors/#mode
connectionStrings
This one really got to me, it was the last one I figured out. After doing a bit of digging I found out that MSDeploy automatically parameterizes certain elements, connection string being one of them, more info here:
Configuring Parameters for Web Package Deployment
My parameter declaration for the connection string in question should have been:
<parameter name="DbConnectionString-Web.config Connection String" defaultValue="">
<parameterEntry kind="XmlFile" scope="\\web.config$" match="/configuration/connectionStrings/add[#name='DbConnectionString']" />
</parameter>
My setParameter definition should have looked like this:
<setParameter name="DbConnectionString-Web.config Connection String" value="Data Source=dbserver;Initial Catalog=DB1;Trusted_Connection=no;User ID=user1;Password=pass*9;" />

Related

Transform app.config entries only if a flag in app.debug.config is true

I would like to perform an xdt:Transform when in Debug configuration but only if the value of an entry in app.debug.config is a certain value, lets say true to keep it simple. For example:
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<add key="Value.First" value="foo" />
<add key="Value.Second" value="foo" />
<add key="Value.Third" value="foo" />
</appSettings>
</configuration>
App.Debug.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<appSettings>
<!--Convenient flag to indicate if transform should happen-->
<add key="Perform.Transform.If.True" value="true" xdt:Transform="Insert" />
<!--Should only happen if the above is true-->
<add key="Value.First" value="bar" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
<add key="Value.Second" value="bar" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
<add key="Value.Third" value="bar" xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
</appSettings>
</configuration>
I would like all of the Value.* entries in app.config to be transformed only if the key Perform.Transform.If.True is set to true. If it is false nothing should happen. The reason being that sometimes during testing we would like to quickly turn things on and off which are controlled by the config files.
I have seen the options for Locator for things like Match, Conditional, XPath, etc. but none seem to allow for a condition from another entry. Can that be done with slowcheetah/xdt transforms?
Well, found a round-about way using XPath:
<add
key="Value.First"
value="bar"
xdt:Transform="Replace"
xdt:Locator="XPath(//appSettings/add[#key='Perform.Transform.If.True' and translate(#value, 'ERTU', 'ertu')='true']/../add[#key='Value.First'])"
/>
If the flag is not true it will fail to resolve the path. The translate makes it case-insensitive.
Failing to resolve (is false) leads to compile warnings which is annoying but since this is a debug tool we can live with that.

Hide value in app.config

I have app.config file with keys and values:
<appSettings>
<add key="Username" value="Admin" />
<add key="Password" value="123456" />
<add key="Port" value="22" />
</appSettings>
I know that best way to secure data in config file is encrypt/decrypt with RSAprovider as web.config then export key and import on another user's machine (I have done this before), but I do not need such "safe" solution.
I just want to hide password value to look like:
<appSettings>
<add key="Username" value="Admin" />
<add key="Password" value="******" />
<add key="Port" value="22" />
</appSettings>
or just like empty string.
I have googled a lot and I could not find anything to hide, but plenty stuff about encryption.
Is this possible to achieve this somehow?
No, app configs are plain text. If you had asterisks instead of the password, they would be interpreted as asterisks.

Server specific Web.config replacement

I am currently using Visual Studio 2010. I want to set up a different connection string for my "Testing" Configuration. I have tried doing it by using config transformations, but it does not seem to work.
In my Web.config my connection string is the following:
<add name="MyDb" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=DevelopmentDb;Integrated Security=SSPI; MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
I found out that you can replace the connection string defined in Web.config by adding config transformation. I right clicked on Web.config and clicked on "Add config transformations". This created a Web.TEST.config file. I then added a connection string replacement, but it doesnt seem to work. It still uses the connection string defined in Web.config.
The file contents of Web.TEST.config is:
<?xml version="1.0"?>
<!-- For more information on using web.config transformation visit http://go.microsoft.com/fwlink/?LinkId=125889 -->
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
<!--
In the example below, the "SetAttributes" transform will change the value of
"connectionString" to use "ReleaseSQLServer" only when the "Match" locator
finds an atrribute "name" that has a value of "MyDB".
-->
<connectionStrings>
<add name="MyDb"
connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=TestDb;Integrated Security=SSPI; MultipleActiveResultSets=True"
xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
</connectionStrings>
<system.web>
<!--
In the example below, the "Replace" transform will replace the entire
<customErrors> section of your web.config file.
Note that because there is only one customErrors section under the
<system.web> node, there is no need to use the "xdt:Locator" attribute.
<customErrors defaultRedirect="GenericError.htm"
mode="RemoteOnly" xdt:Transform="Replace">
<error statusCode="500" redirect="InternalError.htm"/>
</customErrors>
-->
</system.web>
</configuration>
Any ideas to what I could be missing?
Transformations get applied when you deploy the project, not when you compile it.
If you are using IIS, you can deploy to the configured web application directory, which will cause the transform to apply.

MSBuild Paramaters.xml xpath appsettings file attribute

Im using msbuild to create a web deploy package using the parameters.xml file to replace web.config settings.
Im trying to replace the appsettings file attribute in web.config
This is my parameters.xml:
<parameter name="ClientConfig" description="Please enter the clients config file name." defaultValue="Niad.config" tags="">
<parameterEntry kind="XmlFile" scope="\\web.config$" match="/configuration/appSettings/setting[#name='file']/value" />
</parameter>
This is my Web.config section:
<?xml version="1.0"?>
<configuration>
<appSettings file="Client.config">
</appSettings>
</configuration>
I know I'm writing the xpath match incorrectly, I was hoping someone could help me with the correct syntax.
This worked:
match="/configuration/appSettings/#file"
<parameter name="ClientConfig" description="Please enter the clients config file name." defaultValue="Niad.config" tags="">
<parameterEntry kind="XmlFile" scope="\\web.config$" match="/configuration/appSettings/#file" />
</parameter>

getting service from wsdd via xpath not wroking (xmltask)

I am trying to get the XPath "/deployment/service". Tested on this site:
http://www.xmlme.com/XpathTool.aspx
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org /axis/wsdd/providers/java">
<service name="kontowebservice" provider="java:RPC" style="rpc" use="literal">
<parameter name="wsdlTargetNamespace" value="http://strategies.spine"/>
<parameter name="wsdlServiceElement" value="ExposerService"/>
<parameter name="wsdlServicePort" value="kontowebservice"/>
<parameter name="className" value="some.package.internal.KontoWebServiceImpl_WS"/>
<parameter name="wsdlPortType" value="Exposer"/>
<parameter name="typeMappingVersion" value="1.2"/>
<operation xmlns:operNS="http://strategies.spine" xmlns:rtns="http://www.w3.org/2001/XMLSchema" name="expose" qname="operNS:expose" returnQName="exposeReturn" returnType="rtns:anyType" soapAction="">
<parameter xmlns:tns="http://www.w3.org/2001/XMLSchema" qname="in0" type="tns:anyType"/>
</operation>
<parameter name="allowedMethods" value="expose"/>
<parameter name="scope" value="Request"/>
</service>
</deployment>
I absolutely can't find out why it always tells me that my xpath does not match...
This may be stupid, but am I missing something?
EDIT
Thanks to the answer from Dimitre Novatchev I was able to find a workaround:
<xmltask failwithoutmatch="true" report="false">
<fileset dir="${src.gen}/" includes="**/*-deploy.wsdd" />
<copy path="//*[local-name()='service']" buffer="tmpServiceBuf" append="true" />
</xmltask>
<xmltask failwithoutmatch="true" report="false" source="${basedir}/env/axis/WEB-INF/server-config.wsdd" dest="${build.stage}/resources/WEB-INF/server-config.wsdd">
<insert path="//*[local-name()='transport'][last()]" buffer="tmpServiceBuf" position="after" />
</xmltask>
Binding namespaces with xmltask (which is the tool that gave me the headaches) seems not to be possible. The code above did the trick.
The Problem: This XML document has a default namespace. XPath considers any unprefixed names to be in "no-namespace". It tries to select /deployment/service where the elements deployment and service are in no-namespace and doesn't select any node, because in the provided XML documents there are no such elements that are in "no- namespace (they all are in the "http://xml.apache.org/axis/wsdd/" namespace)
The solution: Using the language which hosts XPath (such as C#, Jave, XSLT, or any other language that you may be using) bind a prefix (say x:) to the namespace "http://xml.apache.org/axis/wsdd/".
Then, change:
/deployment/service
to
/x:deployment/x:service
Now the last XPath expression correctly selects the desired node.

Resources