Demystifying physicalDirectory or How to Configure the Site Entry in the Service Definition File for Windows Azure
If you played a bit more with the sites configuration in Windows Azure you may have discovered some inconsistent behavior between what Visual Studio does and what the cspack.exe command line does when it relates to physicalDirecroty attribute. I certainly did! Here is the problem I encountered while trying to deploy PHP on Windows Azure.
Project Folder Structure
I was following the instructions on Installing PHP on Windows Azure leveraging Full IIS Support but decided to leverage the help of Visual Studio instead building the package by hand. Not a good idea for this particular scenario :( After creating my cloud solution in Visual Studio I ended up with the following folder structure:
PHPonAzureSolwas my VS solution folder
PHPonAzurewas my VS project folder containing the CSDEF and CSCFG files
PHPRolewas my VS project folder containing the code for my web role
The PHPRole folder contained the WebPI command line tool needed to install PHP in the cloud stored in the
WebPI-cmd subfolder; the PHP extensions for Azure in the
PHP-Azure subfolder; the installation scripts in the
bin subfolder; and most importantly my PHP pages in
Sites\PHP subfolder (in this case I had simple
index.php page containing
Configuring Site Entry in the CSCFG File
Of course my goal was to configure the site to point to the folder where my PHP files were stored. In this particular case this was the
PHPonAzureSol\PHPRole\Sites\PHP folder if you follow the structure above. This is simply done by adding the
physicalDirectory attribute to the
Site tag in CSDEF. Here is how my
Site tag looked like:
<Site name="Web" physicalDirectory="..\PHPRole\Sites\PHP">
<Binding name="Endpoint1" endpointName="Endpoint1" />
My expectation was that with this setting in CSDEF IIS will be configured to point to the content that comes from the
physicalDirectory folder. Hence if I type the URL of my Windows Azure hosted service I should be able to see the
index.php page (i.e. http://[my-hosted-service].cloudapp.net should point to your PHP code).
Visual Studio handling of physicalDirectory attribute
Of course when I used Visual Studio to pack and deploy my Web Role I was unpleasantly surprised. It seems Visual Studio ignores the
physicalDirectory attribute from your CSDEF file, and points the site to your Web Role’s approot folder (or the content from
PHPRole folder if you follow the structure above). Thus if I wanted to access my PHP page I had to type the following URL:
Not exactly what I wanted :(
The reason for this is that Visual Studio calls
cspack.exe with additional options (either
/sites) that overwrite the
physicalDirectory attribute from CSDEF. As of now I am not aware of a way to change this behavior in VS.
Update (9-12-2011): As it seems VS ignores the
physicalDirectory attribute ONLY if your web site is called Web (i.e.
name="Web" as in the example above). If you rename the site to something else (
name="PHPWeb" for example) you will end up with the expected behavior described below. Unfortunately
name="Web" is the default setting, and this may result in unexpected behavior for your application.
cspack.exe handling of physicalDirectory attribute
Solution to the problem is to call cspack.exe from the command line (without the above mentioned options of course:)).
There are few gotchas about how you call cspack.exe using the folder structure that Visual Studio creates. After few trial-and-errors where I received several of those errors:
Error: Could not find a part of the path '[some-path-here]'.
I figured out that you should call cspack.exe from the solution folder (
PHPonAzureSol in the above structure). Once I did this everything worked fine and I was able to access my
index.php by just typing my hosted service’s URL.
How physicalDirectory attribute works?
For those of you interested how the physicalDirectory attribute works here is a simple explanation.
MSDN documentation for How to Configure a Web Role for Multiple Web Sites points out that
physicalDirectory attribute value is relative to the location of the Service Configuration (CSCFG) file. This is true in the majority of the cases however I think the following two clarifications are necessary:
- Because the attribute is present in the Service Definition (CSDEF) file the correct statement is that
physicalDirectoryattribute value is relative to the location of the Service Definition (CSDEF) file instead. Of course if you use Visual Studio to build your folder structure you can always assume that the Service Configuration (CSCFG) and the Service Definition (CSDEF) files are placed in the same folder. If you build your project manually you should be careful how you set the
physicalDirectoryattribute. This is of course important if you want to use relative paths in the attribute.
- This one I think is much more important than the first one, and it states that you can use absolute paths in the
physicalDirectoryattribute can contain any valid absolute path on the machine where you build the package. This means that you can point
cspack.exeto include any random folder from your local machine as your site’s root.
Here is how this works.
What cspack.exe does is to take the content of the folder configured in
physicalDirectory attribute and copy it under
[role]/sitesroot/[num] folder in the package. Here is how my package structure looked like (follow the path in the address line):
During deployment IIS on the cloud VM is configured to point the site to
sitesroot\[num] folder, and serve the content from there. Here is how it is deployed in the cloud:
And here is the IIS configuration for this cloud VM: