There are times when using IIS that you need to modify settings regarding that Application Pool that your project runs in. In Windows Azure from v1.3 your WebRoles usually run in full IIS, and so some settings that affect your software (say Recycling) are configured outside the scope of your application. In a traditional deployment you may consider modifying the settings manually in IIS Manager, but this is not an option in Azure since the roles may restart and if so will lose your settings. You may also consider modifying applicationHost.confg, which is certainly feasible, but depends upon a startup task outside of the standard web programming model.

This post will show how it is possible to programmatically modify the settings for your Application Pool (appPool). The reasons for choosing this approach are compelling, as your site is not actually created by Windows Azure’s Compute services when other opportune moments occur (the aforementioned startup tasks), and thus you must modify applicationPoolDefaults rather than directly on a single application pool.

Run as Elevated

The first thing we must configure is to start each role with Elevated permissions. This gives the Startup methods more access than they would otherwise have, indeed they may make any modification to the system that they are running on. This initially strikes many people as a dangerous move, but actually the only code that runs Elevated in this scenario is the RoleEntryPoint class, so usually only the OnStart method (and anything you call from it), as a little known tip from Steve Marx points out:

To clarify, running a web role elevated only runs your RoleEntryPoint code elevated, and that happens before the role goes out of the Busy state (so before you’re receiving external traffic).  Assuming you only override OnStart, all the code that runs elevated stops before the website is even up.  I don’t view that as a significant increase in the attack surface.

Steve Marx

To do this, we simply modify our ServiceDefinition.csdef to add a node under our WebRole describing the runtime execution context:

<WebRole name="WebHost">    
     <Runtime executionContext="elevated"/>

Microsoft.Web.Administration

The guts of our work is to be performed by an assembly called Microsoft.Web.Administration. It is a very useful tool that allows for programmatic control of IIS:

The Microsoft.Web.Administration namespace contains classes that a developer can use to administer IIS Manager. With the classes in this namespace, an administrator can read and write configuration information to ApplicationHost.config, Web.config, and Administration.config files.

MSDN

Using this library, we will determine our application’s Application Pool name, and begin setting values as we desire. I must thank Wade Wegner for his excellent post on changing appPool identity, as this forms the basis of my approach.

Firstly instantiate a ServerManager instance, and by building a string that matches our WebRole’s name, we can get a reference to our Application Pool:

using (ServerManager serverManager = new ServerManager())
{
     var siteApplication = serverManager.Sites[RoleEnvironment.CurrentRoleInstance.Id + "_" + webApplicationProjectName].Applications.First();
     var appPoolName = siteApplication.ApplicationPoolName;

     var appPool = serverManager.ApplicationPools[appPoolName];
     // more ...

With this new instance variable “appPool” we can then access and set many property of the Application Pool, just as we might like to do in IIS Manager. For instance, we can make some changes to the way the Application Pool recycles itself:

 
     appPool.ProcessModel.IdleTimeout = TimeSpan.Zero;
     appPool.Recycling.PeriodicRestart.Time = TimeSpan.Zero;

Once we are happy with our modifications, we can commit these changes using:

     serverManager.CommitChanges();

This makes our OnStart method in total (don’t forget a using statement using Microsoft.Web.Administration;):

public override bool OnStart()
{
     // For information on handling configuration changes
     // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.

     var webApplicationProjectName = "Web";

     using (ServerManager serverManager = new ServerManager())
     {
          var siteApplication = serverManager.Sites[RoleEnvironment.CurrentRoleInstance.Id + "_" + webApplicationProjectName].Applications.First();
          var appPoolName = siteApplication.ApplicationPoolName;

          var appPool = serverManager.ApplicationPools[appPoolName];

          appPool.ProcessModel.IdleTimeout = TimeSpan.Zero;
          appPool.Recycling.PeriodicRestart.Time = TimeSpan.Zero;

          serverManager.CommitChanges();
     }

     return base.OnStart();
}

Running this, either locally or in Azure, we can load inetmgr and see the result on the application Pool:

ProcessModel changes once applied

ProcessModel changes once applied

Recycling Changes when applied

Recycling Changes when applied

Conclusion

This technique is a very powerful one, giving you a method to configure the heart of your application’s execution context straight from .net. I hope you find this useful.

I have uploaded a basic project source here: AppPoolProgrammaticModification

The ApplicationPoolDefaults approach

For completeness, should you wish to run this as a startup task instead of programmatically, your command would be something like:

%windir%system32inetsrvappcmd set config -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:0.00:30:00

Andy

About these ads