Wix: How to remove comment in XML file - wix

I have the following config file in my application:
<configuration>
<appSettings>
<!--Setting for user name-->
<add key="wcf:userName" value="wcfuser" />
<!--Setting for password-->
<add key="wcf:userPassword" value="abcdef" />
<!--Setting for is cloud application-->
<add key="IsCloudApplication" value="true" />
</appSettings>
<configuration>
I want remove this comment on the production server via Wix XmlConfig. I tried to use the following code:
<util:XmlConfig Id="RemoveWcfComments" File="[INSTALLFOLDER]Web.config" Action="delete" ElementPath="configuration/appSettings" VerifyPath="<!--Settings for user name-->" Node="element" On="install"/>
,but this is not working: exceptions no occurs, but the comment remains in the config file. Any ideas?
Thank in advance.

I'm not exactly sure but you can try this:
<util:XmlConfig
Id="RemoveWcfComments"
File="[INSTALLFOLDER]Web.config"
Action="delete"
ElementPath="//configuration/appSettings"
VerifyPath="//configuration/appSettings/comment()"
Node="value"
On="install"/>
As you can see ElementPath and VerifyPath are XPath-s, so they are invalid in your code. I'm not sure that Node="value" is right option, you could try Node="element" too.

Using Xpath the Comment() method will select all the the comments underneath AppSettings, if you have multiple comments but want to delete only one, then make use of the xpath below:
VerifyPath="//configuration/appSettings/comment()[.='Settings for user name and password']"
If there are multiple comments and you want to delete the first comment based on the order then you can make use of the below xpath as well:
VerifyPath="//configuration/appSettings/comment()[1]"

Related

Intellij IDEA - DB Navigator - reveal password

I use "DB navigator" plugin(https://plugins.jetbrains.com/plugin/1800-database-navigator/) for my Intellij IDEA Community version quite some time and am very satisfied.
I want to know the password of my DB connection saved in the plugin. They are saved, they are there, but I cannot share it with my teammates.
Even all the IDEA passwords are set to be stored in the system keyring, I don't find them in seahorse, i.e., "Passwords and Keyrings" application in my Ubuntu.
Where are they?
At last, I found it in
<project_root>/.idea/dbnavigator.xml
search your connection name, and you will see sth like this:
<connection id="e208f307-8c08-45d5-93fd-958c1d68d049" active="true">
<database>
<name value="UAT" />
<description value="" />
<database-type value="ORACLE" />
<config-type value="BASIC" />
<database-version value="11.2" />
<driver-source value="BUILTIN" />
<driver-library value="" />
<driver value="" />
<url-type value="SERVICE" />
<host value="some-host" />
<port value="1523" />
<database value="APP_DB" />
<type value="USER_PASSWORD" />
<user value="admin" />
<deprecated-pwd value="<base64-encoded-password>" />
</database>
...
</connection>
So, I tried to base64 decoded them... and it works...
Please, if the author sees this, please don't encrypt it in the future versions; I need them to be in my local so that I don't have to ask my teammates again; too shy am I. Please take into consideration that I created the tag db-navigator for the first time while asking this question, so that ppl around the world could gather together with love of this plugin.
And, any coder reading this: please ignore this file in Git, as it contains sensitive data.

Visual Studio 2015 - Change Setting or Variable at time of Publish

Is it possible to change a setting or variable when the application is published
or is there some sort of condition to run an IF THEN against?
for example, I want to change the way the log files are written when I publish and I often forget to make the change when I publish it
Web.Live.Config:
<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 attribute "name" that has a value of "MyDB".
-->
<appSettings>
<add key="ClaimPackPath" value="C:\\inetpub\\wwwroot\\Application\\ClaimPacks\\" xdt:Locator="Match(key)" xdt:Transform="Replace" />
</appSettings>
</configuration>
Wg.Debug.Config:
<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 attribute "name" that has a value of "MyDB".
-->
<appSettings>
<add key="ClaimPackPath" value="C:\\Debug\\wwwroot\\Application\\ClaimPacks\\" xdt:Locator="Match(key)" xdt:Transform="Replace" />
</appSettings>
</configuration>
Then in the application you can request the variable like so :
string filepath = ConfigurationManager.AppSettings["ClaimPackPath"];
And it will change for whatever publish profile you choose at time of publish :)

How to modify XML file with wix toolset

I have XML file that include a next content:
<!--<appcache appCacheType="None" />-->
<appcache appCacheType="SingleClient" defaultExpiration="3600"/>
On installation patch i need to change this content in XML file to:
<appcache appCacheType="None" />
<!--<appcache appCacheType="SingleClient" defaultExpiration="3600"/>-->
What is a better way to do it?
Thanks.
I tried (in vain) to use the MSI Community Extensions for this purpose, but wasn't able to get them up and running.
I ended up using the util:XmlFile-tag from the Util-extension that works flawlessly.
Add the namespace of the Util-extension to your source-file in the Wix-element:
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
Then use it as sub-element of a related component. In your case you want to delete an attribute and change the value of another one. The following should do the trick, just adjust the XPath in the ElementPath-attribute to the one that matches your tag (in the example it updates the appcache-tag which has an attribute appCacheType with the value SingleClient) and the filekey of the XML-file:
<Component Id="myComponentToUpdateTheXmlFile" ... >
<!-- Removing the defaultExpiration-attribute first -->
<util:XmlFile Id="UpdateAppCacheTag" Action="deleteValue" ElementPath="//appcache[\[]#appCacheType='SingleClient'[\]]/#defaultExpiration" File="[#MyConfigFile.xml]" SelectionLanguage="XPath" Sequence="1" Name="defaultExpiration" />
<!-- Now updating the value -->
<util:XmlFile Id="UpdateAppCacheTag" Action="setValue" ElementPath="//appcache[\[]#appCacheType='SingleClient'[\]]/#appCacheType" File="[#MyConfigFile.xml]" SelectionLanguage="XPath" Sequence="2" Value="None" />
</Component>
Be sure to add the Util-extension also on the commandline when invoking candle and light:
<candle or light command line> ... <parameters> ... -ext <PathToWiXExtensions>\WixUtilExtension.dll
If you want to do this only during e.g. patching, then add the appropriate condition for this component.

How can multiple elements be added to an XML config file with wix?

I am trying to edit an XML file with Wix. I am using the WixUtilExtension bundled with Wix 3.7. The xml file is a settings file created in Visual Studio 2010 for a C# application. In this file, I am using an element which is used to store multiple string values in an array. This is the content of the unaltered settings file:
<configuration>
<applicationSettings>
<AppName.Properties.Settings>
<setting name="StringArray" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</ArrayOfString>
</value>
</setting>
</AppName.Properties.Settings>
</applicationSettings>
</configuration>
I want to add <string> elements to the <ArrayOfString> element in this file. One way to do this is by using an <XmlConfig> element from the wix/UtilExtension namespace. I have added this element to the component which holds the config file like this:
<Component Id="ProductComponent" Guid="$(var.ConfigGuid)">
<File Source="SettingsFile.exe.config" KeyPath="yes" Id="FILE_config" />
<util:XmlConfig
Name="string"
Value="My value"
File="[INSTALLFOLDER]SettingsFile.exe.config"
Id="String1"
On="install"
Action="create"
Node="element"
ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString"
Sequence="100"
/>
</Component>
This results in the addition of one <string> element to the <ArrayOfString> element. To add another <string> element to the settings file, another XmlConfig element has to be added to the <Component> element of the setup project with a different Id attribute and a higher value for the Sequence attribute like this:
<util:XmlConfig
Name="string"
Value="My second value"
File="[INSTALLFOLDER]SettingsFile.exe.config"
Id="String2"
On="install"
Action="create"
Node="element"
ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString"
Sequence="101"
/>
After installation of the msi, the <ArrayOfString> element in the settings file looks like this:
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>My value</string><string>My second value</string></ArrayOfString>
I have found out that it is possible to set the Value attribute of an <XmlConfig> attribute to the value of a property like this:
<Property Id="STRING1VALUE" Value="My value" />
<util:XmlConfig Value="[STRING1VALUE]" ... />
This is good. I would like the user to be able to add multiple values in the installation process dynamically so that a variable amount of <string> elements can be added to the settings file.
My first approach was to use a <?foreach?> statement like this:
<?define values="My value;My second value"?>
<?foreach value in $(var.values)?>
<util:XmlConfig
Name="string"
Value="$(var.value)"
File="[INSTALLFOLDER]SettingsFile.exe.config"
Id="String$(var.value)"
On="install"
Action="create"
Node="element"
ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString"
Sequence="101"
/>
<?endforeach?>
There are a few problems with this approach:
The foreach statement uses a preprocessor variable which cannot be set to the value of a property.
The value of the Sequence attribute stays the same.
I would like the user to store the values for the string elements in a Property which separates the values by semicolons and then parse them in a foreach statement like this:
<Property Id="VALUES" Value="My value;My second value" />
<?foreach value in [VALUES]?>
<util:XmlConfig
Name="string"
Value="$(var.value)"
File="[INSTALLFOLDER]SettingsFile.exe.config"
Id="String$(var.value)"
On="install"
Action="create"
Node="element"
ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString"
Sequence="101"
/>
<?endforeach?>
This throws the following error:
The util:XmlConfig/#Id attribute's value, 'String[VALUES]', is not a legal identifier.
Identifiers may contain ASCII characters A-Z, a-z, digits, underscores (_), or periods (.).
Every identifier must begin with either a letter or an underscore.
Is there any way I can create a variable amount of elements with the XmlFile or the XmlConfig element? Is the only solution to this problem a CustomAction?
Based on Rob's answer, here is my new approach to adding multiple elements to an XML config file with Wix. I did not want to write C++ code, that is why I used DTF in my CustomAction.
I am going to describe how to turn a string containing multiple elements using a delimiter into multiple XML elements.
First there needs to be a property in the setup file containing the delimited string.
<Property Id="STRINGARRAY" Value="string1;string2;string3" />
This property could be populated by the user in a dialog, of course.
Next, a CustomAction has to be written. To make use of the DTF, a reference to the Microsoft.Deployment.WindowsInstaller.dll has to be added to the C# CustomAction project. The namespace Microsoft.Deployment.WindowsInstaller should be included with a using directive in that project. My CustomAction looks like this:
[CustomAction]
public static ActionResult Insert(Session session)
{
string strings = session["STRINGARRAY"];
string[] stringArray = strings.Split(';');
Database db = session.Database;
View view = db.OpenView("select * from `XmlConfig`");
string xpath = "/configuration/applicationSettings/AppName.Properties.Settings/setting[\\[]#name='StringArray'[\\]]/value/ArrayOfString";
for (int i = 0; i < stringArray.Length; i++)
{
string id = String.Format("String{0}", i);
int sequence = 100 + i;
string value = stringArray[i].Trim();
Record rec = new Record(
id,
"[INSTALLFOLDER]SettingsFile.exe.config",
xpath,
null,
"string",
value,
273,
"ProductComponent",
sequence);
view.InsertTemporary(rec);
}
db.Close();
return ActionResult.Success;
}
Here, at first the Property StringArray is read into a local variable which is converted to a string array. The following line establishes a connection to the current database used by the installer. A handle on the table XmlConfig is created, which is the table where the XML elements are added to. To insert the right values into that table, it is best to create an installer file which contains such a table and then take a look at that table in an editor like orca or InstEd.
In the xpath, backslashes have to be escaped by using double backslashes. The id variable holds the name of the temporary record, using a simple string and a number works flawlessly. The sequence has to be incremented for each element. I could not find any documentation on the values of the flags column, but I have found out that its value is set to 273 for elements that are created and 289 for elements that get deleted.
Once the record is filled with the correct values, it gets added to the XmlConfig table by using the InsertTemporary method of the view object. This is done for each element found in the delimited string.
A problem I have come across is that this CustomAction fails, if the XmlConfig table does not exist. To counter this problem I have added the following code to the setup file, which adds an element to the XML file and immediately deletes that element. I guess there could be a cleaner solution, but this was the easiest one for me.
<util:XmlConfig
Name="string"
Value="Dummy"
File="[INSTALLFOLDER]SettingsFile.exe.config"
Id="DummyEntry"
On="install"
Action="create"
Node="element"
ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString"
Sequence="1" />
<util:XmlConfig
On="install"
Action="delete"
Id="DeleteDummyEntry"
Node="element"
File="[INSTALLFOLDER]SettingsFile.exe.config"
VerifyPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString/string"
ElementPath="/configuration/applicationSettings/AppName.Properties.Settings/setting[\[]#name='StringArray'[\]]/value/ArrayOfString"
Sequence="2" />
Finally, the CustomAction has to be added to the setup project. By adding a reference to the CustomAction project in the setup project, the location of the binary can be specified like this:
<Binary Id="XmlCustomActionDLL" SourceFile="$(var.XmlCustomAction.TargetDir)XmlCustomAction.CA.dll" />
The CustomAction has to be executed immediately, otherwise it won't be able to access the session variable:
<CustomAction Id="CA_XmlCustomAction" BinaryKey="XmlCustomActionDLL" DllEntry="Insert" Execute="immediate" Return="check" />
<InstallExecuteSequence>
<Custom Action="CA_XmlCustomAction" Before="RemoveRegistryValues" />
</InstallExecuteSequence>
To determine the right position for the CustomAction in the installation sequence, I relied on this article by Bob Arnson.
Yes, this is possible but if you want to have this determined at install time then the preprocessor is not an option. The preprocessor executes during the build process.
To get what you want, you'll need to write another custom action that takes the arbitrarily long set of user data and adds temporary rows to the XmlConfig table. The WcaAddTempRecord() function in src\ca\wcautil\wcawrap.cpp can do the work. The src\ca\wixca\dll\RemoveFoldersEx.cpp is a pretty good example of using WcaAddTempRecord() to add rows to the RemoveFile table. You'll want to do similarly.

Expiration of NHibernate query cache

Is it possible to configure expiration of NHibernate's query cache?
For second level cache I can do it from nhibernate.cfg.xml, but I can't find a way for SQL query cache.
EDIT:
ICriteria query = CreateCriteria()
.Add(Expression.Eq("Email", identifiant))
.SetCacheable(true)
.SetCacheRegion("X");
<syscache>
<cache region="X" expiration="10" priority="1" />
</syscache>
Yes, we can set cache expiration via region. Adjust the query like this:
criteria.SetCacheable(true)
.SetCacheMode(CacheMode.Normal)
.SetCacheRegion("LongTerm");
And put similar configuration into web.config file
<configSections>
<section name="syscache" type="NHibernate.Caches.SysCache.SysCacheSectionHandler, NHibernate.Caches.SysCache" requirePermission="false" />
</configSections>
<syscache>
<cache region="LongTerm" expiration="180" priority="5" />
<cache region="ShortTerm" expiration="60" priority="3" />
</syscache>
EDIT: I am just adding this link Class-cache not used when getting entity by criteria
To be sure what I mean by SQL Query cache. In the linked answer I am explaining that topic
Just for a clarity. The configuration of the NHibernate "session-factory" must contain:
<property name="cache.use_query_cache">true</property>
This switch will make query cache working. More details: http://nhibernate.info/doc/nh/en/index.html#performance-querycache