DCSIMG
New Full IIS Capabilities: Differences from Hosted Web Core - Windows Azure - Site Home - MSDN Blogs

New Full IIS Capabilities: Differences from Hosted Web Core

New Full IIS Capabilities: Differences from Hosted Web Core

Rate This
  • Comments 11

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:

    <Sites>
      <Site name="Web">
        <Bindings>
          <Binding name="Endpoint1" endpointName="Endpoint1" />
        </Bindings>
      </Site>
    </Sites>

You can easily customise this section to define multiple web sites, virtual applications or virtual directories, as shown in this example:

<Sites>
  <Site name="Web">
    <VirtualApplication name="WebAppA" physicalDirectory="C:\Projects\WebAppA\" />
    <Bindings>
      <Binding name="HttpIn" endpointName="HttpIn" />
    </Bindings>
  </Site>
  <Site name="AnotherSite" physicalDirectory="C:\Projects\AnotherSite">
    <Bindings>
      <Binding hostHeader="anothersite.example.com" name="HttpIn" endpointName="HttpIn"/>
    </Bindings>
  </Site>
</Sites>

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) =>
{
    configSetter(RoleEnvironment.GetConfigurationSettingValue(configName));
});

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.

Conclusion

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.


Comments
  • Great post -- I feel like I would have definitely been incredibly confused by the separate processes and with SetConfigurationSettingsPublisher.

    Quick question, do you see any real benefit to using SetConfigurationSettingsPublisher and FromConfigurationSetting instead of CloudStorageAccount.Parse(RolesEnvironment.GetConfigurationSettingValue(...))?  FromConfigurationSetting seems to be a potential source of confusion for developers since its logic depends entirely on what is in SetConfigurationSettingsPublisher.  This call could be made anywhere in the code and could in theory be setting different logic for different processes.  By comparison, RolesEnvironment.GetConfigurationSettingValue will always work the same way every time its called.

  • Thanks Michael! CloudStorageAccount.FromConfigurationSetting can be useful if you need an abstraction layer around the configuration source - for example if you're building a DLL that could be used in Azure or on-premise. However most of the time I prefer CloudStorageAccount.Parse(RolesEnvironment.GetConfigurationSettingValue(...)) as it's got fewer moving parts and avoids the potential problems mentoned in my post and your comment.

  • When using Full IIS is it possible to start the diagnostic monitor in both the WaIISHost.exe process and the IIS process?  e.g. DiagnosticMonitor.Start called from both WebRole.OnEntryPoint and Application_Start.

    When I try that on my local machine (use the Compute Emulator), I see the following in the trace log:

    Error when updating configuration:System.IO.IOException: All pipe instances are busy.

      at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

      at System.IO.Pipes.NamedPipeServerStream.Create(String fullPipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeAccessRights rights, SECURITY_ATTRIBUTES secAttrs)

      at System.IO.Pipes.NamedPipeServerStream..ctor(String pipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, Int32 inBufferSize, Int32 outBufferSize, PipeSecurity pipeSecurity, HandleInheritability inheritability, PipeAccessRights additionalAccessRights)

      at System.IO.Pipes.NamedPipeServerStream..ctor(String pipeName, PipeDirection direction, Int32 maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options)

      at Microsoft.WindowsAzure.Diagnostics.ConfigChannelServer.Start()

      at Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitor.StartDiagnosticsMonitorProcess(DiagnosticMonitorStartupInfo info)

      at Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitor.ReconfigureMonitoringProcess(ConfigRequest req)

      at Microsoft.WindowsAzure.Diagnostics.ControlChannel.UpdateConfigRequest(Func`2 f); TraceSource 'WaIISHost.exe' event

  • Hi Matthew -

    I haven't seen that error so I'm not sure what causes it, but I'm pretty certain you only need to start the DiagnosticMonitor once (I normally do it in my role startup code) to allow logging across both processes. You still need to add the DiagnosticMonitorTraceListener to both config files though.

    Tom

  • Hello,

    I "really" want to be able to leverage the Full IIS now in Windows Azure by scripting the creation of IIS sites with PowerShell.  Is that possible? I saw elsewhere that you should not make changes in the IIS UI, but that is different.  Is it OK using PowerShell?  I do not want to have to create the sites manually using Visual Studio.

    Thanks!

  • Hello,

    I "really" want to be able to leverage the Full IIS now in Windows Azure by scripting the creation of IIS sites with PowerShell.  Is that possible? I saw elsewhere that you should not make changes in the IIS UI, but that is different.  Is it OK using PowerShell?  I do not want to have to create the sites manually using Visual Studio.

    Thanks!

  • This is the one I'm looking for, Thank a lot.

    BTW, I have a questions.

    First, after I read "What is Full IIS?" section, It seem I can use ServiceDefinition.csdef similar to ApplicationHost.config. (refer to www.iis.net/ConfigReference)

    but in Window Azure environment bring me more question. Where do I place WebAppA folder? C:\Projects\WebAppA\? Is it another Compute Instance such as Web Role or Worker Role or VM. I'm not so sure. Could you explain that or share some link?

  • I just found out answer to my previous question.

    here useful links

    http://blog.smarx.com/posts

    msdn.microsoft.com/.../gg433110.aspx

    msdn.microsoft.com/.../gg433059.aspx

    hope this help,

    pat

  • DE (sorry for the slow reply) - yes it's possible to script IIS configuration in Azure. You can define a startup task to run under elevated privileges, and then use appcmd.exe to query and modify the IIS configuration. However you should only need to do this for advanced configuration - for basic things such as creating sites and virtual applications it's best to define these declaratively in ServiceDefinition.csdef.

    Tom

  • Is it really full IIS? Well I can log in to the role VM using RDP and configure IIS the way i want but all that is voluntary and when the role restarts.. everythying is gone. Through site configuration you can really achieve so much.

    The scenario i was trying to build was deploy a web app as one site and WCF services exposed on named pipes on another site.. but for a web role it doesnt allow to expose endpoint on named pipe? How do i achieve this?

    Regards

    Badal

  • Subtle differences == fertile ground for nasty gotchas. The description on this page is typical Azure Team blase ("it's so easy you don't even need to think about it, but you'll quickly find yourself in pain and have no alternative but to think really hard".

    I was surprised that creating an Azure C# web project did not include a README that described the separation of processes :- I imagine everyone who selects this option spends some cycles figuring out WTF is going on.

    Subtle things turn out to be hard under Full IIS on Azure:

    - files under roleroot are not accessible by default inside IIS, running under a different account.

    - Debugging startup errors in Application_Start (hint executes before VS debugger attaches to w3wp.exe).

    - Debugger conflicts when VS attempts to connect to w3wp when user already has a debugger attached to it

    - How to get trace logging working from inside W3WP.exe? Did you waste time initializing logger inside the webrole? Doh?

Page 1 of 1 (11 items)
Leave a Comment
  • Please add 8 and 1 and type the answer here:
  • Post