Debugging Azure Web Roles with Custom HTTP Headers and Self-Registering HttpModules

Standard

For the past year-and-a-half, I’ve been helping customers to develop web applications targeting Windows Azure PaaS. Typically, customers ask lots of similar questions and these are usually because they’re faced with similar challenges (there really isn’t such a thing as a bad question). I’ve recently had to answer this very question a few times in succession, so I figured that makes it a good candidate for a blog post! As always, I’d love to get your feedback and if you find this tip useful I’ll try to share some more common scenarios soon.

The scenario I want to focus on here today is nice and quick. It’s a reasonably common scenario in which you’ve deployed a web application (let’s say, a WebAPI project) to Azure PaaS and have more than a handful of instances serving-up requests.

Sometimes it’s tricky to determine which role instance served-up your request

When you’re developing and testing, you quite often need to locate the particular node which issued a an HTTP response to the client.

When the total number of instances serving your application are low, cycling through one or two instances of a web role (and connecting up to them via RDP) isn’t a particular issue. But as you add instances you don’t typically know which server was responsible for servicing the request, thus you have more to check or ‘hunt through’. This can make it more difficult for you to quickly jump to the root of the problem for further diagnosis.

Why not add a custom HTTP header?

In a nutshell, one possible way to help debugging calls to an API via HTTP is to have the server inject a custom HTTP header into the response which emits the role instance ID. A switch in cloud configuration (*.cscfg) can be added which allows you to turn this feature on or off, so you’re not always emitting it. The helper itself (as you’ll see below) is very lightweight and you can easily modify it to inject additional headers/detail into the response. Also, emitting the role instance ID (i.e. 0, 1, 2, 3 …) is preferable to emitting the qualified server name, for security reasons, and doesn’t really give too much info away to assist a would-be attacker.

How’s it done?

It’s rather simple and quick, really. And, you can borrow the code below to help you out but do remember to check it meets your requirements and test it thoroughly before chucking it into production! We start by creating an HTTP module in the usual way:

public class CustomHeaderModule : IHttpModule
    {

        public static void Initialize()
        {
            HttpApplication.RegisterModule(typeof(CustomHeaderModule));
        }

        public void Init(HttpApplication context)
        {
            ConfigureModule(context);
        }

        private void ConfigureModule(HttpApplication context)
        {
            // Check we're running within the RoleEnvironment and that
            // our configuration setting ("EnableCustomHttpDebugHeaders") is present. This is our "switch", effectively...
            if (RoleEnvironment.IsAvailable && RoleEnvironment.GetConfigurationSettingValue("EnableCustomHttpDebugHeaders"))
            {
                context.BeginRequest += ContextOnBeginRequest;
            }
        }

        private void ContextOnBeginRequest(object sender, EventArgs eventArgs)
        {
            var application = (HttpApplication)sender;
            var response = application.Context.Response;

            // Inject custom header(s) for response

            var roleName = RoleEnvironment.CurrentRoleInstance.Role.Name;
            var index = RoleEnvironment.Roles[roleName].Instances.IndexOf(RoleEnvironment.CurrentRoleInstance);
            response.AppendHeader("X-Diag-Instance", index.ToString());
        }

        public void Dispose()
        {
        }
    }

What we’ve got here is essentially a very simple module which injects the custom header, “X-Diag-Instance”, into the server’s response. The value for the custom header will be the index of the instance of the role in the Instances collection property of Role.

Deploying the module

Then, we want to add a little magic to have the module self-register at runtime (sure, you can put this in config if you really want to). This is great, because you could put the module into a shared library and then simply have it register itself into the pipeline automatically. Of course, you could actually substitute the config switch for a check to determine whether the solution is in debug or release mode, too (customise it to fit your needs).

To do the self-registration, we rely on a little known but extremely useful ASP.NET 4 extensibility feature called PreApplicationStartMethod. Decorating the assembly with this attribute allows the .NET framework to discover your module and auto-register it:

[assembly: PreApplicationStartMethod(typeof(PreApplicationStartCode), "Start")]
namespace MyApplication
{
    public class PreApplicationStartCode
    {
        public static void Start()
        {
            Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(CustomHeaderModule));
        }
    }

    public class CustomHeaderModule : IHttpModule
    {
      // ....
    }
}

This approach also works well for any custom headers you want to inject into the response, and a great use case for this would be to emit custom data you want to collect as part of a web performance or load test.

I hope you find this little tip and the code snippet useful, and thanks to @robgarfoot for the pointer to the super useful self-registration extensibility feature!