The Adoption Program Insights series describes experiences of Microsoft Services consultants involved in the Windows Azure Technology Adoption Program assisting customers deploy solutions on the Windows Azure platform. This post is by Tom Hollander.
The new Windows Azure SDK 1.3 supports Full IIS, allowing your web roles to access the full range of web server features available in an on-premise IIS installation. However if you choose to deploy your applications to Full IIS, there are a few subtle differences in behaviour from the Hosted Web Core model which you will need to understand.
What is Full IIS?
Windows Azure's Web Role has always allowed you to deploy web sites and services. However many people may not have realised that the Web Role did not actually run the full Internet Information Services (IIS). Instead, it used a component called Hosted Web Core (HWC), which as its name suggests is the core engine for serving up web pages that can be hosted in a different process. For most simple scenarios it doesn't really matter if you're running in HWC or IIS. However there are a number of useful capabilities that only exist in IIS, including support for multiple sites or virtual applications and activation of WCF services over non-HTTP transports through Windows Activation Services.
One of the many announcements we made at PDC 2010 is that Windows Azure Web Roles will support Full IIS. This functionality is now publicly available and included in Windows Azure SDK v1.3. To tell the Windows Azure SDK that you want to run under Full IIS rather than HWC, all you need to do is add a valid <Sites> section to your ServiceDefinition.csdef file. Visual Studio creates this section by default when you create a new Cloud Service Project, so you don't even need to think about it!
A simple <Sites> section defining a single website looks like this:
<Binding name="Endpoint1" endpointName="Endpoint1" />
You can easily customise this section to define multiple web sites, virtual applications or virtual directories, as shown in this example:
<VirtualApplication name="WebAppA" physicalDirectory="C:\Projects\WebAppA\" />
<Binding name="HttpIn" endpointName="HttpIn" />
<Site name="AnotherSite" physicalDirectory="C:\Projects\AnotherSite">
<Binding hostHeader="anothersite.example.com" name="HttpIn" endpointName="HttpIn"/>
After working with early adopter customers with Full IIS for the last couple of months, I've found that it's now easier than ever to port existing web applications to Windows Azure. However I've also found a few areas where you'll need to do things a bit differently to you did with HWC due to the different hosting model.
New Hosting Model
There is a significant difference in how your code is hosted in Windows Azure depending on whether you use HWC or Full IIS. Under HWC, both the RoleEntryPoint methods (e.g. the OnStart method of your WebRole class which derives from RoleEntryPoint) and the web site itself run under the WaWebHost.exe process. However with full IIS, the RoleEntryPoint runs under WaIISHost.exe, while the web site runs under a normal IIS w3wp.exe process. This can be somewhat unexpected, as all of your code belongs to the same Visual Studio project and compiles into the same DLL. The following diagram shows how a web project compiled into a binary called WebRole1.dll is hosted in Windows Azure under HWC and IIS.
This difference can have some unexpected implications, as described in the following sections.
Reading config files from RoleEntryPoint and your web site
Even though the preferred way of storing configuration in Windows Azure applications is in the ServiceConfiguration.cscfg file, there are still many cases when you may want to use a normal .NET config file - especially when configuring .NET system components or reusable frameworks. In particular whenever you use Windows Azure diagnostics you need to configure the DiagnosticMonitorTraceListener in a .NET config file.
When you create your web role project, Visual Studio creates a web.config file for your .NET configuration. While your web application can access this information, your RoleEntryPoint code cannot-because it's not running as a part of your web site. As mentioned earlier, it runs under a process called WaIISHost.exe, so it expects its configuration to be in a file called WaIISHost.exe.config. Therefore, if you create a file with this name in the your web project and set the "Copy to Output Directory" property to "Copy Always" you'll find that the RoleEntryPoint can read this happily. This is one of the only cases I can think of where you'll have two .NET configuration files in the same project!
Accessing Static Members from RoleEntryPoint and your web site
Another implication of this change is that any AppDomain-scoped data such as static variables will no longer be shared between your RoleEntryPoint and your web application. This could impact your application in a number of ways, but there is one scenario which is likely to come up a lot if you're migrating existing Windows Azure applications to use Full IIS. If you've used the CloudStorageAccount class before you've probably used code like this to initialise an instance from a stored connection string:
var storageAccount = CloudStorageAccount.FromConfigurationSetting("ConnectionString");
Before this code will work, you need to tell the CloudStorageAccount where it should get its configuration from. Rather than just defaulting to a specific configuration file, the CloudStorageAccount requires you set a delegate that can get the configuration from anywhere you want. So to get the connection string from ServiceConfiguration.cscfg you could use this code:
CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
If you're using HWC with previous versions of the SDK (or if you deleted the <Sites> configuration setting with SDK 1.3), you can happily put this code in WebRole.OnStart. However as soon as you move to Full IIS, the call to CloudStorageAccount.FromConfigurationSetting will fail with an InvalidOperationException:
SetConfigurationSettingPublisher needs to be called before FromConfigurationSetting can be used
"But I did call it!" you'll scream at your computer (well at least that's what I did). And indeed you did-however you called it in an AppDomain in the WaIISHost.exe process, which has no effect of your web site hosted in an entirely different AppDomain under IIS. The solution is to make sure you call CloudStorageAccount.SetConfigurationSettingPublisher and CloudStorageAccount.FromConfigurationSetting within the same AppDomain, most likely from your web site. While there used to be some issues with accessing Windows Azure SDK classes in your Application_Start event, these no longer apply and this is a great place to initialise your configuration setting publisher.
Or alternatively, as long as you're happy to use the ServiceConfiguration.cscfg file for your connection strings, you can avoid setting up this delegate altogether by replacing the call to CloudStorageAccount.FromConfigurationSetting(...) with this:
var storageAccount = CloudStorageAccount.Parse(RoleEnvironment.GetConfigurationSettingValue("ConnectionString"));
Securing resources for different web sites and applications
One final thing to note is that if you configure your Web Role to run multiple sites or virtual applications, each will run in its own Application Pool and under its own user account. This provides you with a lot of flexibility-for example you could grant different virtual applications with access to different resources such as file system paths or certificates. If you want to take advantage of this you can leverage another new SDK 1.3 feature and specify a startup task to run under elevated privileges. This task could launch a PowerShell script that sets access control lists which allows each of your applications to access the resources it needs.
The option to use Full IIS with Windows Azure Web Roles gives you access to a lot of new functionality that makes it easier to migrate existing IIS-based applications and also gives you more options when developing new applications. With a better understanding of the underlying hosting and security model, I hope you're able to use these new features with fewer development headaches.