Gaurav Mantri's Personal Blog.

Programmatically finding Deployment Slot from code running in Windows Azure

I’ve seen a number of threads on MSDN forums for Windows Azure where folks want to know if their application is running in “Production” or “Staging” slot in a Windows Azure hosted service. There may be situations where you don’t want your code to execute certain functionality when it is running in the “Staging” environment and thus at times it becomes important to find this information out.

By its design, Windows Azure does not differentiate between a “Staging” and a “Production” deployment. Also it does not expose any means to find that information programmatically through managed library as well. However, one way to find this information is by using Service Management API.

The process is rather simple. Using Service Management API, first find out the list of all hosted services in your subscription (http://msdn.microsoft.com/en-us/library/ee460781.aspx). Next step would be to get the properties of each of these hosted services (with “embed-detail=true” query string parameter) to get the deployment details (http://msdn.microsoft.com/en-us/library/ee460806.aspx) and find the matching deployment id (available through “RoleEnvironment.DeploymentId” variable).

If you’re interested in the source code, here it is. If you want you can download Project Source Code as well.

ServiceManagementRestHelper.cs: This class has .Net wrapper around Service Management REST API.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security.Cryptography.X509Certificates;
using System.Net;
using System.Xml.Linq;
using System.IO;

namespace WebRole1
{
    public static class ServiceManagementRestHelper
    {
        private static string versionNumber = "2011-10-01";
        private static XNamespace wa = "http://schemas.microsoft.com/windowsazure";
        private static string getHostedServicesOperationUrlTemplate = "https://management.core.windows.net/{0}/services/hostedservices";
        private static string getHostedServicePropertyOperationUrlTemplate = "https://management.core.windows.net/{0}/services/hostedservices/{1}?embed-detail=true";

        public static IList GetHostedServices(string subscriptionId, X509Certificate2 certificate)
        {
            List hostedServiceNames = new List();
            string uri = string.Format(getHostedServicesOperationUrlTemplate, subscriptionId);
            XElement xe = PerformGetOperation(uri, certificate);
            if (xe != null)
            {
                var serviceNameElements = xe.Elements().Elements(XName.Get("ServiceName", wa.ToString()));
                foreach (var serviceElement in serviceNameElements)
                {
                    hostedServiceNames.Add(serviceElement.Value);
                }
            }
            return hostedServiceNames;
        }

        public static XElement GetHostedServiceProperties(string subscriptionId, X509Certificate2 certificate, string hostedServiceName)
        {
            string uri = string.Format(getHostedServicePropertyOperationUrlTemplate, subscriptionId, hostedServiceName);
            return PerformGetOperation(uri, certificate);
        }

        private static HttpWebRequest CreateHttpWebRequest(Uri uri, X509Certificate2 certificate, String httpWebRequestMethod)
        {
            HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
            httpWebRequest.Method = httpWebRequestMethod;
            httpWebRequest.Headers.Add("x-ms-version", versionNumber);
            httpWebRequest.ClientCertificates.Add(certificate);
            httpWebRequest.ContentType = "application/xml";
            return httpWebRequest;
        }

        private static XElement PerformGetOperation(string uri, X509Certificate2 certificate)
        {
            XElement responseBody = null;
            Uri requestUri = new Uri(uri);
            HttpWebRequest httpWebRequest = CreateHttpWebRequest(requestUri, certificate, "GET");
            using (HttpWebResponse response = (HttpWebResponse)httpWebRequest.GetResponse())
            {
                Stream responseStream = response.GetResponseStream();
                responseBody = XElement.Load(responseStream);
            }
            return responseBody;
        }
    }
}

Webrole.cs: Among other things, this class exposes a static function which calls the REST API helper functions to get the information.

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using System.Security.Cryptography.X509Certificates;
using System.Net;
using System.Xml.Linq;
using System.IO;
using System.Text;

namespace WebRole1
{
    public class WebRole : RoleEntryPoint
    {
        public override bool OnStart()
        {
            // For information on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
            return base.OnStart();
        }

        public static RoleDetails GetRoleDetails()
        {
            RoleDetails roleDetails = null;
            string subscriptionId = RoleEnvironment.GetConfigurationSettingValue("SubscriptionId");
            string certificateData = RoleEnvironment.GetConfigurationSettingValue("ManagementCertificate");
            X509Certificate2 certificate = new X509Certificate2(Convert.FromBase64String(certificateData));
            IList hostedServices = ServiceManagementRestHelper.GetHostedServices(subscriptionId, certificate);
            string deploymentId = RoleEnvironment.DeploymentId;
            if (hostedServices != null && hostedServices.Count > 0)
            {
                foreach (var hostedService in hostedServices)
                {
                    XElement xe = ServiceManagementRestHelper.GetHostedServiceProperties(subscriptionId, certificate, hostedService);
                    if (xe != null)
                    {
                        var deploymentXElements = xe.Elements(XName.Get("Deployments", "http://schemas.microsoft.com/windowsazure")).Elements(XName.Get("Deployment", "http://schemas.microsoft.com/windowsazure")).ToList();
                        if (deploymentXElements != null && deploymentXElements.Count > 0)
                        {
                            foreach (var deployment in deploymentXElements)
                            {
                                string currentDeploymentId = deployment.Element(XName.Get("PrivateID", "http://schemas.microsoft.com/windowsazure")).Value;
                                if (currentDeploymentId == deploymentId)
                                {
                                    string deploymentSlotName = deployment.Element(XName.Get("DeploymentSlot", "http://schemas.microsoft.com/windowsazure")).Value;
                                    roleDetails = new RoleDetails()
                                    {
                                        HostedServiceName = hostedService,
                                        DeploymentSlot = deploymentSlotName,
                                        DeploymentId = RoleEnvironment.DeploymentId,
                                    };
                                    break;
                                }
                            }
                        }
                    }
                    if (roleDetails != null)
                    {
                        break;
                    }
                }
            }
            return roleDetails;

        }
    }

    public class RoleDetails
    {
        public string HostedServiceName
        {
            get;
            set;
        }

        public string DeploymentSlot
        {
            get;
            set;
        }

        public string DeploymentId
        {
            get;
            set;
        }
    }
}

I’m pretty sure that there are other and better ways to accomplish this. This is one way to accomplish this. Feel free to add your comments.

Hope this helps.

Code Courtesy: Neil Mackenzie (@mknz) has been kind enough to allow me to use some of the code from his blog (http://convective.wordpress.com). He is a Windows Azure MVP (par excellence, might I add) and the author of a fabulous book “Microsoft Windows Azure Development Cookbook” (http://convective.wordpress.com/2011/08/08/microsoft-windows-azure-development-cookbook/). If you’re doing or planning on doing any development work on Windows Azure, I would recommend you read his book and subscribe to his blog.


[This is the latest product I'm working on]