With version 1.3 of the Azure SDK, it became possible to run multiple and composite websites inside a single Web Role. This is achieved using the features many web developers are familiar with from IIS:
- Web Site
- Virtual Applications
- Virtual Directories
If you’re not familiar with the nuances of what you can and can’t achieve with each of these types of IIS entity the subtler details (particularly between the last two) are described in a detailed blog by Wenlong Dong.
Above, I made a differentiation between Multiple Web Sites and Composite Web Sites. This I mean to be that Multiple Web Sites are two input endpoints, such as a website running on a different port or on the same port with a host header separating incoming traffic. Composite Web Sites I mean to be a single Web Site running on a single endpoint (say port 80) but with different applications running in subdirectories of the website (http://blog.bareweb.eu and http://blog.bareweb.eu/myApplication1/). These can be configured at the same time, and I will start off describing Composite Web Sites and move onto Multiple WebSites.
The new functionality in 1.3 is very powerful, and a game changer when it comes to the financial outlay that Azure represents – you can suddenly use a single role to host a number of lightweight applications and maintain their separation. However, the feature at the time of writing is not particularly well documented, and so I will run through an example of how to achieve the required configuration.
Composite Web Sites
Firstly, create a new Azure Project and add a single Web Role.
This gives you a basic application and all the required ServiceDefinition and ServiceConfiguration files. We will be modifying the ServiceDefinition.csdef file later in order to enable the multiple roles.
For now, we should create the other web sites that we want to run as a VirtualDirectory or VirtualApplication. It may be the case that you are already have applications that you want to add in, and so you have to use “Add Existing Web Site”. However, I am adding new, so I right-click on the solution in Solution Explorer, select Add and then New Web Site …
I will add two new Websites to the solution, one as a VirtualApplication and one as a VirtualDirectory. When you are creating these projects (or adding Existing) it is worth bearing in mind that the paths of the solutions should be trivially relative to the path of the ServiceDefinition.csdef file, as if you choose to use relative paths then this is the relative base of the path. Firstly, create the ChildVirtualApplication website.
Then we can create an ASP.NET Empty Web Site that will be used for our VirtualDirectory. In this example I’ll put an image in the project but little else, as a common use for Virtual Directories is to bring in shared assets or other such items.
It’s important to note that we added these sites DIRECTLY into the solution, not using the Azure Tools to add new Roles, as doing so is not what we are trying to achieve.
Once we’ve added these sites, our Solution will look as below:
Now, if we started our application we would only get the MasterWebRole running. There would be no way of accessing the AssetsVirtualDirectory or ChildVirtualApplication through the DevFabric. The same would apply if we deployed to Azure, only MasterWebRole would be transferred and would run. Note: with the default configuration you will be able to access the new Web Sites through the ASP.NET Development Server, but this is not through Azure Dev Fabric and so is not what we really want.
You can configure your projects not to start the ASP.NET Development Server by right-clicking each of the new Projects and selecting the following options:
To resolve this, we need to actually modify the ServiceDefinition.csdef file to enable the multiple websites within the WebRole. This sentence actually describes quite what we have to do, we need to find the <WebRole/> node and within that the <Sites/> child node. Inside this, there should be one <Site/> defined, with a value similar to the below:
<Site name="Web"> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" /> </Bindings> </Site>
This shows a single Site, with a single Endpoint, which exactly matches our experience when we start our application. What we really want is for the new Web Sites we added to our Project to run on subdirectories off the root of the MasterWebRole application:
- / runs MasterWebRole
- /Child/ runs ChildVirtualApplication
- /Assets/ runs AssetsVirtualDirectory
We can achieve this very simply by adding VirtualDirectory and VirtualApplication nodes to the <Site/> node listed above. Firstly we will add in the /Child/ VirtualApplication, note that as earlier mentioned, the relative path is relative to the ServiceDefinition.csdef file and so may vary depending on where you place your Web Sites. You can use Absolute paths if you find it easier.
The xml to set up the VirtualApplication is:
<VirtualApplication name="child" physicalDirectory="../ChildVirtualApplication" />
The name property specified the subdirectory that we can use to access VirtualApplication, the physicalDirectory is the path to the child application.
The xml to set up the Virtual Directory is:
<VirtualDirectory name="assets" physicalDirectory="../AssetsVirtualDirectory" /> This makes the <Site/> node complete, look like: <Site name="Web"> <VirtualApplication name="child" physicalDirectory="../ChildVirtualApplication" /> <VirtualDirectory name="assets" physicalDirectory="../AssetsVirtualDirectory" /> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" /> </Bindings> </Site>
Now, when we launch the DevFabric application, we can navigate to “/child/” and request the image at “/assets/Images/Azure.png” and the files are request successfully via DevFabric.
And in the Child Application:
Multiple Web Sites
In the example up to now, we have only shown what can be achieved within a single <Site/>. This will let you add a new site that runs at the root of the domain, which may be a requirement for some applications. To do this, we will need to add a new SecondMasterSite, as so:
Once we have this SecondMasterSite available, we will create a new entry for it in the ServiceDefinition.csdef and add in a new <Binding/> and associated <InputEndpoint/>so that we can load the new Site on a brand new port.
<Site name="Second" physicalDirectory="../SecondMasterSite"> <Bindings> <Binding name="Endpoint2" endpointName="Endpoint2" /> </Bindings> </Site>
…
<InputEndpoint name="Endpoint2" protocol="http" port="81" />
In this way we can specify that the new Endpoint should run on port 81. Note that when using DevFabric, the actual port that the application runs on may vary if the port requested is not available.
We are free to add in additional VirtualDirectories and VirtualApplications into this second Site just as we are with the first one. Therefore we can bring in the assets and child application from the first example into the second.
<Site name="Second" physicalDirectory="../SecondMasterSite"> <VirtualApplication name="child" physicalDirectory="../ChildVirtualApplication" /> <VirtualDirectory name="assets" physicalDirectory="../AssetsVirtualDirectory" /> <Bindings> <Binding name="Endpoint2" endpointName="Endpoint2" /> </Bindings> </Site> This gives us the <WebRole/> node as follows - note that the Imports Diagnostics is not important for this example: <WebRole name="MasterWebRole"> <Sites> <Site name="Web" physicalDirectory="../MasterWebRole"> <VirtualApplication name="child" physicalDirectory="../ChildVirtualApplication" /> <VirtualDirectory name="assets" physicalDirectory="../AssetsVirtualDirectory" /> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" /> </Bindings> </Site> <Site name="Second" physicalDirectory="../SecondMasterSite"> <VirtualApplication name="child" physicalDirectory="../ChildVirtualApplication" /> <VirtualDirectory name="assets" physicalDirectory="../AssetsVirtualDirectory" /> <Bindings> <Binding name="Endpoint2" endpointName="Endpoint2" /> </Bindings> </Site> </Sites> <Endpoints> <InputEndpoint name="Endpoint1" protocol="http" port="80" /> <InputEndpoint name="Endpoint2" protocol="http" port="81" /> </Endpoints> <Imports> <Import moduleName="Diagnostics" /> </Imports> </WebRole>
Now when we run this, Visual Studio will automatically load a new web browser for our new InputEndpoint (helping us determine the port if it is not exactly as specified).
You may receive an error when running this, due to the web.config not allowing compilation for debug by default. Change the System.WebCompilation attribute to debug=”true” if you get this error:
This gives the below operating website (on port 82 for me):
Once you overcome this issue (if you encountered it at all), you can begin to consider some more advanced ways of differentiating InputEndpoints. For example, it is not necessary to differentiate between <Site/> entries using a port – instead you can use host headers – the HTTP header send by requesting browsers to an application which includes the domain name they are trying to access. IIS is able to detect this header and automatically route traffic to the correct website based on this, even when the sites are running on the same port. Therefore you do not need to run on separate ports, but instead can use a single InputEndpoint, but specify different hostheaders as per the below. Note that for this to work, you should set up DNS entries that match the remote IP addresses, or for local use, modify the HOSTS file.
<WebRole name="MasterWebRole"> <Sites> <Site name="Web" physicalDirectory="../MasterWebRole"> <VirtualApplication name="child" physicalDirectory="../ChildVirtualApplication" /> <VirtualDirectory name="assets" physicalDirectory="../AssetsVirtualDirectory" /> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="www.firstwebsite.com" /> </Bindings> </Site> <Site name="Second" physicalDirectory="../SecondMasterSite"> <VirtualApplication name="child" physicalDirectory="../ChildVirtualApplication" /> <VirtualDirectory name="assets" physicalDirectory="../AssetsVirtualDirectory" /> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="www.secondwebsite.com" /> </Bindings> </Site> </Sites> <Endpoints> <InputEndpoint name="Endpoint1" protocol="http" port="80" /> </Endpoints> <Imports> <Import moduleName="Diagnostics" /> </Imports> </WebRole>
Packaging for Azure
So far your DevFabric will be running perfectly well, but the eagle eyed amongst you will notice that each application is actually running directly off the source. This isn’t ideal, and if you were to try to deploy this to Azure you would be deploying the source directly. Instead, you should publish each of your WebSites to a location and then reference these files. I achieve this simply by adding a new folder at the same level as all of the new applications called “Publish” (path from ServiceDefinition.csdef is “../Publish/”) and then publishing each application to there. This makes updating the ServiceDefinition.csdef easy, as “../SecondMasterSite” simply becomes “../Publish/SecondMasterSite”.
The benefit of not Packaging is that you can make changes at runtime in some cases to the applications, but you must always remember to republish locally before you deploy to Azure.
<WebRole name="MasterWebRole"> <Sites> <Site name="Web" physicalDirectory="../MasterWebRole"> <VirtualApplication name="child" physicalDirectory="../Publish/ChildVirtualApplication" /> <VirtualDirectory name="assets" physicalDirectory="../Publish/AssetsVirtualDirectory" /> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="www.firstwebsite.com" /> </Bindings> </Site> <Site name="Second" physicalDirectory="../Publish/SecondMasterSite"> <VirtualApplication name="child" physicalDirectory="../Publish/ChildVirtualApplication" /> <VirtualDirectory name="assets" physicalDirectory="../Publish/AssetsVirtualDirectory" /> <Bindings> <Binding name="Endpoint1" endpointName="Endpoint1" hostHeader="www.secondwebsite.com" /> </Bindings> </Site> </Sites> <Endpoints> <InputEndpoint name="Endpoint1" protocol="http" port="80" /> </Endpoints> <Imports> <Import moduleName="Diagnostics" /> </Imports> </WebRole>
Finally
I hope this has been a useful reference. The documentation for this at the time of writing is not entirely clear, but what I did find useful was the Service Definition Schema reference. For further reading, you can try the training kit.
I have attached my solution to this post. It is not packaged for Azure and so should work straight away on DevFabric. MultipleWebSites













Great article. I am running into a problem with multiple sites where I want to run the site at the root level. Instead of having to add a new site or existing site to the project, I just want to reference it in the physicalDirectory attribute of the site node. However, when I run it it doesn”t look at the physicalDirectory path but instead runs the web role default.aspx page. Any insights would be greatly appreciated!
Hi NewAzureUser
Does it work locally? The point of adding the new or existing site to the project is so that it gets packaged and transferred to Azure as part of the uploaded programs that eventually run as roles. It could be that since you”re not adding it to the project, Visual Studio is not “bundling” the files and packaging them for deployment. When DevFabric runs, it will create entries in IIS for you, and you can see them in inetmgr. Use this to debug any problems you may be having with IIS setup:
Note that if you got into the details of these, you”ll find the port that they”re really running on, and so you can see that DevFabric is providing a load balancer that sits over the top of these ports.
You don”t need to keep a one to one relationship with the sites in your ServiceDefinition.csdef – you should be able to reference the same one project multiple times, in the same way as I reuse code within the VirtualDirectory nodes in this article.
When you create multiple sites, you either create them on a new port (and thus a new InputEndpoint) or a host header. Adding new sites does not mean that they will be automatically loaded in a web browser for you – this only happens for each InputEndpoint, so if you are using ports to differentiate the services then the site should open automatically, but they”re not opened in a browser if you are using host headers. Try navigating to their host header manually.
Andy
Hi
I go throug this demo. It was great. I have similar kind of problem
I have a web role in Azure application which is on http. Now I want in my existing web role that it should have functionality of ADFS authentication using federation of a particular trustedIssuer. So I added one more web role just for authentication with https endpoint with trustedIssuer’s certificate. And after ADFS authentication redirecting to previous http url.
My problem is that in local emulation it is redirecting to https:// web role but while deploying in production environment no one site is running
Please help me for this
Hi Anurag
I am looking to do an ADFS authentication post soon. Watch this space!
Andy
Hi
I go throug this demo. It was great. I have similar kind of problem
I have a web role in Azure application which is on http. Now I want in my existing web role that it should have functionality of ADFS authentication using federation of a particular trustedIssuer. So I added one more web role just for authentication with https endpoint with trustedIssuer’s certificate. And after ADFS authentication redirecting to previous http url.
My problem is that in local emulation it is redirecting to https:// web role but while deploying in production environment no one site is running
Please help me for this
Hi Anurag
I am looking to do an ADFS authentication post soon. Watch this space!
Andy
This worked perfectly
This worked perfectly
Hi,
I am able to make it run for multiple websites. very useful article.
But not sure, how can i make use of WCF Service like a website….
e. g. I have a WCF Service (.svc file running) & i have asp.net master project. Can i treat WCF Project as like asset project in your example.
If no, why?
if yes, how….
Thanks
Rajeev Singh
Hi Rajeev,
You can configure the WCF hosting master project as a Virtual Directory in IIS in exactly the same ways as I did for the Asset project. Once you have the WCF project running successfully, simply configure it as a Virtual Directory and then everything should work. Do you have a specific problem with running the WCF project as a Virtual Directory?
Andy
Hi,
I am able to make it run for multiple websites. very useful article.
But not sure, how can i make use of WCF Service like a website….
e. g. I have a WCF Service (.svc file running) & i have asp.net master project. Can i treat WCF Project as like asset project in your example.
If no, why?
if yes, how….
Thanks
Rajeev Singh
Hi Rajeev,
You can configure the WCF hosting master project as a Virtual Directory in IIS in exactly the same ways as I did for the Asset project. Once you have the WCF project running successfully, simply configure it as a Virtual Directory and then everything should work. Do you have a specific problem with running the WCF project as a Virtual Directory?
Andy
I”m not able to hit any breakpoints in projects that are added as virtual applications. This is probably because of the issue you point out in the 2nd to last section “Packaging for Azure”. Any guesses on how to get the debugger attached?
I”ve not had chance to test this, but I presume the problem lies with the debugger attaching to IIS.
You could try attaching it manually to additional w3wp.exe you see in the process list.
I”ll investigate it when I can.
Andy
Yeah, I can see my dll when I manually attach to w3wp.exe but I”m having a bit of trouble loading symbols for the module. Whenever I try to load a pdf file that should be correct, I get the message “A matching symbol file was not found in this folder”
I”m not able to hit any breakpoints in projects that are added as virtual applications. This is probably because of the issue you point out in the 2nd to last section “Packaging for Azure”. Any guesses on how to get the debugger attached?
I”ve not had chance to test this, but I presume the problem lies with the debugger attaching to IIS.
You could try attaching it manually to additional w3wp.exe you see in the process list.
I”ll investigate it when I can.
Andy
Yeah, I can see my dll when I manually attach to w3wp.exe but I”m having a bit of trouble loading symbols for the module. Whenever I try to load a pdf file that should be correct, I get the message “A matching symbol file was not found in this folder”
I am getting the following error while running this application.
Error:The XML specification is not valid: The element ‘Site’ in namespace ‘http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition’ has invalid child element ‘VirtualApplication’ in namespace ‘http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition
Having the same problem. Please address this. Cannot find workaround as of yet.
Hey very cool site!! Guy .. Excellent .. Superb .. I will bookmark your website and take the feeds also?I’m satisfied to find a lot of helpful information right here within the submit, we’d like develop more strategies on this regard, thanks for sharing. . . . . .
thanks .. very helpful article..
when i publish multiple websites to azure with only single role, I get single default url to browse in the azure management portal. How can I browse two sites using single url? I have deployed apps into staging. Further my cloud service name is bwservice, so the production url is like bmservice.cloudapp.net, First website host header is http://www.bmadminsite.com and my second website hostheader is http://www.bmclientsite.com. Can these be different from production url?
Hello
I hope you can cast some clarification on this topic for me. I am trying to host a cms (composite c1) on azure with mvc 4 subsites. The composite c1 system comes as a visual studio project: http://docs.composite.net/WindowsAzure/Azure-Only/Source-Code
The solution contains two projects, a webrole and a azure project.
Publising it works fine. I then used your article to try getting a subsit running also and this is what i have done:
1) Add a new project, asp.net mvc4 internet site.
2) Edit the Service Definition.csdef
I published the mvc project site to the publish folder first.
3) I checed the size of the packaged created with the azure project with and without the virtual directory, 5mb vs 8 mb. It looks like something more is packaged down atleast.
4) Publish to azure.
5) myapp.cloudservice.net works(the composite c1 site). but myapp.cloudservice.net/MvcApplication1/ returns 404 – File or directory not found.
6) Remote accessing azure instance and looks into ISS, i find the composite site, but I cant locate the mvc application anywhere, nor see any virtual directories.
Please ask me if i left something out, but i would really love to get this working. Such i can host my main site and then just host some subsites in the same webrole and save some money.
Hi NewAzureUser
Does it work locally? The point of adding the new or existing site to the project is so that it gets packaged and transferred to Azure as part of the uploaded programs that eventually run as roles. It could be that since you”re not adding it to the project, Visual Studio is not “bundling” the files and packaging them for deployment. When DevFabric runs, it will create entries in IIS for you, and you can see them in inetmgr. Use this to debug any problems you may be having with IIS setup:
Note that if you got into the details of these, you”ll find the port that they”re really running on, and so you can see that DevFabric is providing a load balancer that sits over the top of these ports.
You don”t need to keep a one to one relationship with the sites in your ServiceDefinition.csdef – you should be able to reference the same one project multiple times, in the same way as I reuse code within the VirtualDirectory nodes in this article.
When you create multiple sites, you either create them on a new port (and thus a new InputEndpoint) or a host header. Adding new sites does not mean that they will be automatically loaded in a web browser for you – this only happens for each InputEndpoint, so if you are using ports to differentiate the services then the site should open automatically, but they”re not opened in a browser if you are using host headers. Try navigating to their host header manually.
Andy