Vdirs folder came from nowhere?

Topics: IIS and Web Services, Server Deployment
May 12, 2011 at 7:46 PM

When I install the MSI, there is a phantom folder name being created that I don't see actually specfied anywhere in my config or the btdf targets file: Vdirs

My config file looks like so:

    <VDirList Include="*">
      <AppPool>ASP.NET v4.0</AppPool>

The install places the folder from my configuration above under this "Vdirs" subfolder in the deployment root location. 

The problem is, <CreateVirtualDirectory> creates a path based on $(MSBuildProjectDirectory\%(VDirList.Physdir) but that expression doesn't contain any "Vdirs" path string - it

is something like C:\installdir\Deployment\IISVirtualDirectory

Is this introduction of a "Vdirs" subfolder something I can control? 


Wouldn't we rather the <Physdir> path be honored (relative to the project root) both in local deployment mode as well as MSI deployment mode? Or do I have something else out of whack? I do notice that I was taking a non-standard approach to local deployment in that I put the virtual directory underneath the main Deployment folder (i.e. IISVirtualDirectory is a sibling of MyProj.btdfproj).


May 12, 2011 at 8:12 PM

Looking at source, the installer does appear to have this hardcoded?

In MSBuildBased\Framework\BizTalkDeploymentFramework.WiXSetup.targets

Line 65:     <MakeDir Directories="$(RedistDir)\Vdirs\%(VDirList.Physdir)" Condition="'$(IncludeVirtualDirectories)' == 'true'" />

Looks like that's how I'm getting this extra subfolder? Is this perhaps a bug? I mean, I don't see how my server deployment  and the local dev deployment could ever both succeed

if both use %(VDirList.Physdir) to set virtual directory path, yet in the MSI case it sneaks in an additional hardcoded "Vdirs" in the path.

Is there something special about this "Vdirs" folder, or can we just remove it from this .targets file?

May 13, 2011 at 6:05 AM

The short answer is that you should simply move your virtual directory folder up one level.

The virtual directory folders were intended to live under the solution root, not under the deployment project folder.  When they live under the solution root, <Physdir> is always something like ..\VDirFolderName.  On a dev deployment, that relative path resolves one level up from the Deployment project folder.  On a server, we need the vdir folder to remain in that same position relative to the Deployment project folder.  To accomplish that, when the files are copied for the MSI, a bogus "Vdirs" folder is added to the destination path.  At copy time, when the path is resolved to a physical folder, the .. from <Physdir> cancels out the bogus Vdir folder, causing the actual destination to be at the root of the redist folder -- and in the correct position relative to the Deployment project folder once the MSI is installed.  So it's a relative path trick to get the folder in the right place whether locally or on a server.


May 16, 2011 at 5:43 PM

Ahh.  Maybe paraphrasing your answer in the documentation would be useful.

I did like the idea of everything related to deployment (including virtual directory info in my case) was tucked in under my "Deployment" folder, but moving the virtual directory portion up to the solution root did (logically enough) resolve my issue.


Nov 9, 2012 at 2:58 AM

Hi Tom,

When we create a VDIr using following snippet.

 <VDirList Include="*">

My scenario is to create the physical directory on C:\inetpub\wwwroot\myVDR but it is erroring out because of it creates the VDir in the obj\redist folder under the solution root. How can I create the physical directory on C:\inetpub\wwwroot\myVDR during my server deployment. In this case my Virtual Directory in IIS should point to this physical path instead of default installation directory path.

It is legitimate requirement and I am wondering why BTDF is not giving this option. Am I missing something?

Nov 9, 2012 at 3:52 AM

The Deployment Framework bundles everything that your application needs to run into an MSI, but it installs the files into a single destination folder on the target server.  The <Physdir> is hard-coded to be relative to the directory containing the .btdfproj on the server.

If you would like to change that behavior, you can copy and paste the DeployVDirs Target from the BizTalkDeploymentFramework.targets file into your own .btdfproj and modify it.  That allows you to avoid modifying any BTDF files.

I'm going to make an assumption that you're on IIS6 or IIS7, and I know you are using a web service, so you might end up with this:

<Target Name="DeployVDirs" DependsOnTargets="SetWinVer;GetSoftwarePaths" Condition="'$(IncludeVirtualDirectories)' == 'true'">
	<!-- Deploy virtual directories and handle service account assignment. -->

	<CreateVirtualDirectory MetabasePath="$(IISMetabasePath)" Name="%(VDirList.Vdir)" Path="%(VDirList.Physdir)" />

	<!-- Make sure aspnet account can read physical directory & its contents.  
		 For workstation deployments, you would need to supply the account value through an MSBuild property. -->
	<Message Text="Modifying NTFS permissions on virtual directory folders..." Condition="'$(ModifyNTFSPermissionsOnVDirPaths)' == 'true'" />
	<!-- Take the username value from install wizard if doing a formal install -->
	<Exec Command="cacls &quot;%(VDirList.Physdir)&quot; /E /G $(VDIR_UserName):R"
		  Condition="'$(ModifyNTFSPermissionsOnVDirPaths)' == 'true' and ('$(IisMajorVersion)' == '6' or '$(IisMajorVersion)' == '7') and '$(Configuration)' == 'Server'" />
	<Exec Command="cacls &quot;%(VDirList.Physdir)\*.*&quot; /E /G $(VDIR_UserName):R"
		  Condition="'$(ModifyNTFSPermissionsOnVDirPaths)' == 'true' and ('$(IisMajorVersion)' == '6' or '$(IisMajorVersion)' == '7') and '$(Configuration)' == 'Server'" />

	<Exec Command="cacls &quot;%(VDirList.Physdir)&quot; /E /G $(AppPoolAccount):R"
		  Condition="'$(ModifyNTFSPermissionsOnVDirPaths)' == 'true' and ('$(IisMajorVersion)' == '6' or '$(IisMajorVersion)' == '7') and '$(Configuration)' != 'Server'" />
	<Exec Command="cacls &quot;%(VDirList.Physdir)\*.*&quot; /E /G $(AppPoolAccount):R"
		  Condition="'$(ModifyNTFSPermissionsOnVDirPaths)' == 'true' and ('$(IisMajorVersion)' == '6' or '$(IisMajorVersion)' == '7') and '$(Configuration)' != 'Server'" />
	<Message Text="Done modifying NTFS permissions on virtual directory folders." Condition="'$(ModifyNTFSPermissionsOnVDirPaths)' == 'true'" />

	<!-- Create app pool and place vdir in app pool for win2003 -->
	  MetabasePath="$(IISMetabasePath)" VDirName="%(VDirList.Vdir)" AppPoolName="%(VDirList.AppPool)"
	  Condition="('$(IisMajorVersion)' == '6' or '$(IisMajorVersion)' == '7')" />
	  MetabasePath="$(IISMetabasePath)" AppPoolName="%(VDirList.AppPool)" UserName="$(VDIR_UserName)" Password="$(VDIR_UserPass)"
	  Condition="('$(IisMajorVersion)' == '6' or '$(IisMajorVersion)' == '7') and '$(Configuration)' == 'Server'" />

	<!-- Set the .NET runtime version on the AppPool if AppPoolNetVersion was specified; IIS 7.0+ only -->
	<Exec Command="&quot;$(AppCmd)&quot; set apppool /apppool.name:&quot;%(VDirList.AppPool)&quot; /managedRuntimeVersion:%(VDirList.AppPoolNetVersion)"
		  Condition="'$(IisMajorVersion)' == '7' and '$(Configuration)' == 'Server' and '%(VDirList.AppPoolNetVersion)' != ''" />

This will override the default implementation.