Deploy PDB files into production to ease exception report investigation.


 For a long time I believed that PDB as a part of debugging information should not be included in production deployment. Recently my colleague suggested to copy them to simplify exception investigations. 


The following  SO discussion convinced us that it is a good idea  ( at least for web sites).

    These files will not be exposed to the public if kept in the right places (websitebin). 

 So we decided to deploy the PDBs into production.

BTW, if you include PDBs with your deployments, you don’t need to store them in a symbol server,

 as it is suggested in

However we found that  PDBs   were generated not for all DLLs.  After some analysis we believe that MS changed default settings starting from VS 2008 (or may be since VS 2005) and make generation of PDB-only even for release mode. This is why older projects had generation of PDBs disabled.

To change setting in Visual Studio there is an option in the “Project Properties”, “Build”, “Advanced…”.

Change “Debug Info:” to PDB-only.

The screenshots are available in the post


Related links:
The article compares different options for debug and release and confirms that in 2007 pdbonly was the default for release configuration of visual studio   

/optimize+ /debug:pdbonly (release configuration of visual studio)

The article Include .pdb files in Web Application Publish for Release mode (VS2012)  wasn’t applicable for us, but may be useful for someone else.

Using CTT to modify config files for different environments

We previously tried to use msbuild to adjust configuration files for different environments.

Recently I found

onfig Transformation Tool(CTT) on CodePlex

and with

addition of global replace using powershell

it is enough and easier to do all required modifications

Content of ChangeConfig.cmd:

ctt s:..web.config t:WebConfig.CTT d:..web.config

powershell.exe -command “Get-Content ..Remoting.config | ForEach-Object { $_ -replace ‘//localhost/ServicesCI/’, ‘//ServerName01/ServicesCI/’ } | Set-Content ..remoting.temp”

powershell.exe -command “copy  ..remoting.temp ..remoting.config”

ctt s:..EnterpriseLibraryLogging.config t:EnterpriseLibraryLogging.CTT d:..EnterpriseLibraryLogging.config

@goto end

@rem some code that currently not used



Content of example




key=”ShowDeveloperExceptionInfo” value=”False” xdt:Transform=”Replace”  xdt:Locator=”Match(key)” />




name=”ServiceModelMessageLoggingListener” initializeData=”C:temptestCIcopy2.svclog”   xdt:Locator=”Match(name)” xdt:Transform=”SetAttributes(initializeData)”   />




Extract from web.config –
sharedListeners section


initializeData=”C:tempTEST.svclog” type=”System.Diagnostics.XmlWriterTraceListener, System, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089″ name=”ServiceModelMessageLoggingListener” traceOutputOptions=”Timestamp”>

type=”” />



MSbuild Task FileUpdate to replace content in text files

I wanted to replace some strings in files using my deployment MSbuild script.

I’ve noticed that MSBuild Community Tasks Project has RegexReplace task.

But when I’ve looked in documentation 

(By the way, it will be good if Reference help will be available online, not only from download)

I’ve realized that the task is applicable for strings(e.g file names) not to content within a file.

Almost accidently in one of the posts i’ve found a reference to FileUpdate
task, that support Regex and does content replacements within a file.

The following examle (from downloaded help) search for a version number and update the revision.

            <FileUpdate Files="version.txt"
                ReplacementText="$1.$2.$3.123" />

Note: don’t forget to insert in to your project

<Import Project=”MSBuild.Community.Tasks.Targets”/>

You may require to change MSBuildCommunityTasksPath if it is not in current directory.

EntitySpaces API: How to get esQueryItem column name.

In constructor columnName is passed as parameter.

public esQueryItem (
	esDynamicQuery query,
	string columnName
However I wasn't able to fint the property ColumnName or something similar.
After some time I understood, that they use implicit operator string
public static implicit operator string  (
	esQueryItem item
which does the magic.
However  the explicit read-Only property ColumnName will be useful.

By the way the help shows 2 different operators as the same
static memberImplicit(esQueryItem)
ToString() (to use in GroupBy/OrderBy and such ....)

static memberImplicit(esQueryItem)
ToString() (to use in GroupBy/OrderBy and such ....)

Error in WEBCA_SetTARGETSITE during installation of Web Setup Project on Vista.

I have a MSI package created using Visual Studio 2005 Web Setup Project on Windows 2003 Server.

When I tried to install it on Vista(home premium) with IIS7 installed, the setup failed with

Action ended: WEBCA_SetTARGETSITE. Return value 3.

Fortunately, when I’ve  installed  the optional “IIS 6 Management Compatibility” option within IIS7, the installation succeeded.

Update appSettings in App.Config for executable.

I wanted programmatically (for administrator) to update configuration settings for .Net 2.0 executable.
The new  in VS 2005 Properties.Settings class saves only user-scope settings, not application scope, which is inconvinient.

I’ve decided to use The easiest way to read/write AppSettings   from the very good article Read/Write App.config with .NET 2.0/Enterprise Library   However I noticed two issues:

 config.AppSettings.Settings (KeyValueConfigurationCollection class) has Add and Remove methods, but does not have Set method, so I had to create static helper function:
        public static void Set(KeyValueConfigurationCollection settings, string key, string value)

            if (settings[key] != null)




            settings.Add(key, value);



Also if the appSettings element uses the File attribute,

config.Save() for executable updates the main file, not specified in File attribute “appSettings” section.So if the value is stored in the referenced file, saving “appSettings” to the main file has no effect.


Invoke Executable as custom action during Install.

I’ve used MS Installer class to provide custom  actions during setup in a few projects(e.g.see Using VS 2005 Web Setup Project with custom actions).
However if you have some complex logic to do as a part of setup, it is possible that some exception will occur.
I don’t like to hide exceptions, and they are shown to the user,causing installation to rollback.
It is not good, becuse sometimes user wants to ignore exception and use installation even if some custom action failed.
I found that moving code from custom action to executable gives more flexibility,as well as allow to use the same program to customize installation later just by running the same exe.
The Visual Studio SetupProject allowes to specify Custom Action as executable,not as Installer Class.
However during Uninstall,Repair etc, Executable Custom Action can be invoke not as programmer initially designed,and it is required to specify conditions for custom actions. Unfortunately, I had a lot of problems trying to set correct conditions(see Custom action condition to run for a new or upgraded product.and Intermittent execution of custom action for installation of product upgrade. )

To avoid these problems with  Executable Custom Action I desided to return back to Installer Class Custom action, but in Install method the only task is to start  executable and executable will do all required customization of installation.
You can see the code of the class here.

Batch to Logging Worker Process Recycling Events in IIS 6.

I want to log Worker Process Recycling Events in IIS 6.0 (IIS 6.0) , but ther is no UI for this.
I’ve created batch file and decided to post it here, because current instructions have a few typos.
You should modify value of AppPoolName as appropriate.

:rem IISLoggingWorkerProcessRecycling.bat
:rem from
set EnableEvent=true
set AppPoolName=ASP.NET v2.0
cd %systemDRIVE%inetpubadminscripts
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleTime” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleRequests” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleSchedule” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleMemory” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleIsapiUnhealthy” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleOnDemand” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecycleConfigChange” %EnableEvent%
cscript adsutil.vbs set “w3svc/AppPools/%AppPoolName%/AppPoolRecyclePrivateMemory” %EnableEvent%


Intermittent execution of custom action for installation of product upgrade.

I’ve recently posted Custom action condition to run for a new or upgraded product., but I found that the custom action doesn’t always call executable.
 I removed any custom action conditions, but it still doesn’t always produced the same result
I had to install ORCA, and found that my Custom Action has source _5C6AF63299974A76AD78EA44FCE751A6 (reference to MSIAssembly table ) and type 1042(Custom Action Type 18 + msidbCustomActionTypeInScript 1024)
The CustomAction guid key has entry in InstallExecuteSequence table with condition $C__5C6AF63299974A76AD78EA44FCE751A6>2  and sequence 5999.
According to Conditional Statement Syntax. $component-action >2 means Action state of the installed locally or run from the source.
It means that sometimes installer doesn’t recognize that a component is installed( I still don’t understand the pattern??). 
Actually according to Custom Action Tutorial  Custom Action runs only when the component is being added(or deleted).

Custom action condition to run for a new or upgraded product.

I have a custom action condition (in Visual Studio Web Setup Project) that I want  to run for installation of a new or upgraded product. I do not want to run it on repair (and also during uninstall).

First of all I tried “Not Installed” condition. But it doesn’t work for version upgrade. I’ve tried

Not Remove=”ALL” but it also doesn’t work for version upgrade( it seems that deleting previous version set the property Remove=”ALL”)

I’ve tried UPGRADINGPRODUCTCODE , but it is set for the previous version, not for the version being installed.

The article (sorry, in Russian only) suggests to use IS_MAJOR_UPGRADE ,but the property is applicable for InstalledShield only.

Finally I found combination that is working:

Note that brackets are important to evaluate NOT first and condition is case-sensitive).

PREVIOUSVERSIONSINSTALLED is not documented property, I found it when reading msi log and in a few posts(e.g. here: “If the search at the start of the install detects
an older version, it creates the PREVIOUSVERSIONSINSTALLED property,
case-sensitive.“ ).

NOTE: I found that custom action with condition
(Not Installed) OR PREVIOUSVERSIONSINSTALLED works on my development machine, but it was not invoked on my deployment machine until I changed target virtual directory. Mistery ???