US/UK | Contact
cats


July 2010Hosting WCF services (with HTTP endpoints) in Windows Azure worker roles

There is a big buzz around all things Cloud Computing – and obviously Microsoft also wants its part of the cake. We at thinktecture have been spending a lot of time researching the Windows Azure platform offering, including all relevant parts like Windows Azure Compute, Windows Azure Storage, SQL Azure, Claims-based security & identity management and the Windows Azure platform AppFabric with the Access Control Service (ACS) and the Service Bus. 

For those people interested into getting more insight into the Windows Azure family, we partnered with DevelopMentor and dm is offering a course “Cloud Computing for .NET Developers: The Windows Azure platform”. Go and check it out.
 
Note: The approach outlined below currently only works with Internal endpoints, not Input endpoints.
Anyway, let’s hop over to the actual problem I ran into the other day. My goal was to self-host some of my WCF services with HTTP-based endpoints in a Windows Azure worker role – should be easy, eh? 
Turned out that it was easy. Once you consider using the Azure API to get the actual endpoint to listen on (which obviously you need to specify/model in the service’s .csdef file), like this:
using System;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.ServiceModel;
using System.Threading;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Services;
namespace WCFWorkerRole
{
    public class WorkerRole : RoleEntryPoint
    {
        private ServiceHost host;
        public override void Run()
        {
            Trace.WriteLine("WCFWorkerRole entry point called", "Information");
            while (true)
            {
                Thread.Sleep(10000);
                Trace.WriteLine("Working", "Information");
            }
        }
        public override bool OnStart()
        {
            ServicePointManager.DefaultConnectionLimit = 12;
            DiagnosticMonitor.Start("DiagnosticsConnectionString");
            StartWCFService();
            RoleEnvironment.Changing += RoleEnvironmentChanging;
            return base.OnStart();
        }
        public override void OnStop()
        {
            StopWCFService();
            base.OnStop();
        }
        private void StartWCFService()
        {

IPEndPoint ip = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints[

"WCFService"].IPEndpoint;
 
Uri baseAddress = new Uri(String.Format("http://{0}", ip));
 
            try
            {
                host = new ServiceHost(typeof(HelloService), baseAddress);
                host.Open();
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, "Error");
                throw;
            }
            Trace.WriteLine("WCF Hello service running...");                       
        }
        private void StopWCFService()
        {
            if (host != null)
            {
                try
                {
                    host.Close();
                }
                catch (Exception ex)
                {
                    Trace.WriteLine(ex.Message, "Error");
                    host.Abort();
                    throw;
                }
            }
        }
        private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                e.Cancel = true;
            }
        }
    }
}
 

 

Make sure you start your WCF service in OnStart – Steve has a good explanation why.
When I run the worker role in the dev fabric everything looks fine:
 
WCF service in worker role in local dev fabric
 
Cool – so let’s deploy it into the cloud.
 
Deploying WCF Service worker role from VS2010
 
<17 minutes later… /> 
Argh – we get an exception when our WCF service wants to start in Windows Azure! What happened?
 
IntelliTrace when trying to start WCF service in Windows Azure

OK. The root cause of this problem is that Azure creates an “IP-bound Weak Wildcard” HTTP reservation using the IP address of the modeled endpoint. But by default, WCF attempts to bind to the “Strong Wildcard”, leading to a reservation problem as seen in the exception text. Our WCF binding must be compatible with the reservation. Currently, the only known way is to use the Exact hostname comparison mode.

We can do this in code or in config. Let’s – for the sake of simplicity - just use BasicHttpBinding to illustrate this:
var b = new BasicHttpBinding
{ 
  HostNameComparisonMode = HostNameComparisonMode.Exact 
};
 

Or in config:

 
<bindings>
  <basicHttpBinding>
    <binding name="basicHttp"
       hostNameComparisonMode="Exact" />
  </basicHttpBinding>
 

And as I am a big fan of custom bindings this is what I had to do to get my sample from above working with my custom binary-over-http binding:

 
<bindings>
  <customBinding>
    <binding name="binaryHttp">
      <binaryMessageEncoding />
      <httpTransport 
         hostNameComparisonMode="Exact" />
    </binding>
  </customBinding>
</bindings>
 
Christian Weyer is co-founder of thinktecture , a European company aiding and supporting software architects and developers in designing and implementing distributed solutions architectures.

He was selected as one of the Microsoft MVPs for Solution Architecture and is an independent Microsoft Regional Director.  Christian is the co-author of DevelopMentor's Pragmatic Cloud Computing for .NET Developers Training course.