Alright then – lets move the WCF service to the cloud!

Scenario – This is another take on my “Sunny or Cloudy” metro application we developed in my first post. We will make it visually appealing! And how do I plan to do that? Have you noticed how in the TV forecast, they show you weather information overlapped on a map of the area – something like the following:

image

Well, we will use the same concept and deploy a WCF service in Azure which given a zip code, will give us an area map and the weather information about it. Following is the screenshot from our finished metro client application: 

image

I passed the zip code of Manhattan area of New York city and got back the area’s Bing maps link and the weather information which I am showing overlapped on the map. (It surely has cleared up there after snowing over the weekend – a surprise snow storm early in October itself!) 

WCF service :

The WCF service, which we will be deploying in Azure, will act as an aggregator of information will be developed in .net 4.0 so that we can deploy it in Azure. Following diagram shows its architecture:

image

  • Metro client application users will enter a zip code.
  • This zip code will be sent to the WCF service deployed in Azure. The service will be deployed in a web role with BasicHttpBinding and hence accessible over http and we will configure it with TransportWithMessageCredential security mode so that we can use username/password credentials to authenticate the metro client.
  • This WCF service will use HttpClient library (This is a NuGet package for the HtpClient functionality for .Net 4.0, HttpClient is only available in .Net 4.5) to make calls to the Bing Maps REST APIs to fetch a link to the map of the area.
  • The Azure WCF service will also call out to an external ASMX weather service to get the weather details. Notably – this weather webservice returns back an image url describing the weather conditions which we will use to overlay on the area map.  This is the ‘sunny’ weather image link in the metro client screenshot above on top of the Manhattan area map.

1. So we start with an Azure Cloud application project and add a WCF Service WebRole. You need to download the “Windows Azure Tools for Microsoft Visual Studio” for this.

imageimage

2. Next, we define the service and the data contract for the Azure WCF service:

Code Snippet
  1. [ServiceContract]
  2. public interface IWeatherInfo
  3. {
  4.     [OperationContract]
  5.     WeatherInfo GetWeatherInfo(string inputZip);
  6. }
  7.  
  8. [DataContract]
  9. public class WeatherInfo
  10. {
  11.     [DataMember]
  12.     public string Locality { get; set; }
  13.     
  14.     [DataMember]
  15.     public string WeatherDescription { get; set; }
  16.     
  17.     [DataMember]
  18.     public string WeatherImageUri { get; set; }
  19.     
  20.     [DataMember]
  21.     public string MapImageUri { get; set; }
  22. }

The service contract is straightforward – it takes a zip code and returns a data contract consisting of the members we will use in the metro client to display the area and weather information.

3) To make calls to the Bing Maps REST APIs – I have chosen to use the HttpClient so we need to download the HttpClient NuGet reference.

imageimage

4) And to make calls to the external weather web service – http://wsf.cdyne.com/WeatherWS/Weather.asmx, we need to add a service reference to it.

image

5) I’ll let you explore the implementation of the WCF service by downloading the sample code from below. Few highlights of the code though -

a) The code below shows how we are creating a WCF client proxy to talk to the weather ASMX webservice and making a call to it using the zip code passed to the service method call:

Code Snippet
  1. WeatherInfo returnResults = new WeatherInfo();
  2. WeatherWebservice.WeatherSoapClient weatherProxy = new WeatherWebservice.WeatherSoapClient("WeatherSoap");
  3. WeatherWebservice.WeatherReturn weatherResults = new WeatherWebservice.WeatherReturn();
  4.  
  5. // Call the weather web service to get weather information
  6. weatherResults = weatherProxy.GetCityWeatherByZIP(inputZip);

b) The code below shows how we are using the HttpClient API to make a call to the Bing Maps REST API. You will need to register with the Bing Maps (http://www.bingmapsportal.com/) to get a developer key to use the maps APIs.

To get the area map url - I needed to make a couple of these REST calls – one to get the latitude/longitude of the area given a zip code and the next to get the a maps image url feeding it the latitude/longitude I retrieved from the first call.

Code Snippet
  1. // Use the Web APIs HttpClient to access Bing Maps REST service to get the city map
  2. string bingMapsKey = "<enter your bing maps key";
  3.  
  4. HttpClient client = new HttpClient();
  5. string bingMapsPointDataQuery = String.Format
  6.     ("http://dev.virtualearth.net/REST/v1/Locations?countryRegion=US&postalCode={0}&o=xml&key={1}",
  7.         inputZip, bingMapsKey);
  8. HttpResponseMessage bingMapsPointsData = client.Get(bingMapsPointDataQuery);

6. Lets configure security on our Azure WCF service:

a. Open up the WCF service web.config and add an https protocol mapping -

Web.config Snippet
  1. <protocolMapping>
  2.   <remove scheme="http" />
  3.   <add binding="basicHttpBinding" bindingConfiguration="secureBinding" scheme="https" />
  4. </protocolMapping>

We are removing the http access of the WCF service and restricting it to https.

b. Next configure the binding to use TransportWithMessageCredential security mode and UserName client credential type. This will allow us to pass a username/password from the metro client to authenticate.

Web.config Snippet
  1.   <binding name="secureBinding">
  2.     <security mode="TransportWithMessageCredential">
  3.       <message clientCredentialType="UserName" />
  4.     </security>
  5.   </binding>
  6. </basicHttpBinding>
Code Snippet
  1. <behaviors>
  2.   <serviceBehaviors>
  3.     <behavior name="">
  4.       <serviceMetadata httpsGetEnabled="true" />

We are also configuring httpsGetEnabled on the serviceMetadata behavior to allow us to expose the service metadata over https exclusively.

c. Next, we will add a custom userNamePasswordValidator so that we can validate the credentials passed by the Metro client.

Code Snippet
  1. public class MyCustomUserNamePasswordValidator : UserNamePasswordValidator
  2. {
  3.     public override void Validate(string userName, string password)
  4.     {
  5.         if (userName != "myAzureUsername" || password != "myAzurePassword")
  6.         {
  7.             throw new FaultException("Invalid credentials");
  8.         }
  9.     }
  10. }

This is just a hard coded credentials check for demo purpose! Next we need to wire this custom username/password validator to the service by adding a serviceCredentials service behavior.

Web.config Snippet
  1.     <!-- Adding custom username password validator -->
  2.     <serviceCredentials>
  3.       <userNameAuthentication userNamePasswordValidationMode="Custom"
  4.                               customUserNamePasswordValidatorType="WCFServiceWebRole.MyCustomUserNamePasswordValidator, WCFServiceWebRole" />
  5.     </serviceCredentials>
  6.   </behavior>
  7. </serviceBehaviors>

7. Now the fun part – configuring certificates which can be used by our Azure WCF service for the configured transport security. We will use self-signed certificates for this purpose. http://msdn.microsoft.com/en-us/library/cc949067.aspx is an excellent link which walks you through this – showing how to create a root certificate authority certificate (Step 1) which you will then need to install in the Trusted Root Certificate Authority of the Win8 machine (Step 2) from where the Metro client makes its call and finally creating the service certificate from the root certificate (Step 3). This service certificate will be used for SSL communication between the client and the server. Step 4 in the above walkthrough is not needed as it is IIS specific.

Make sure that you are substituting the <machineName> with the name where you will be deploying your WCF service in Azure (e.g. in my case it was piyushjoWeatherService.cloudapp.net)

image

This is required because this certificate is going to be used by our WCF service deployed in Azure at this host name and therefore when the Metro client will attempt to establish an SSL connection with this service, WCF client will ensure that the subject name of the certificate with which the WCF service it is talking to is configured matched exactly with the hostname it is using to make the service call. This is identical to how you configure if your service was hosted on premise – where you need to make sure that the certificate is issued to a subject name matching the machine name where the service is hosted.

For actual production deployment you would go to a certificate authority like VeriSign to provide you a certificate with the subject name where you will be deploying your service so no need to create these self-signed certificates. You will also not need the Step 2 from above link to deploy the root certificate in the Trusted Root authority store because trusted root certificates from reputed authorities like VeriSign are already installed there. 

8. Finally we add the certificate to the WCF web role and configure the Azure WCF service web role to expose an https endpoint and use the certificate we just created to provide SSL security for this https endpoint.

image

image

9. Lastly we create a package for the Azure WCF service and deploy it to an Azure production deployment along with the certificate. The final deployment will look like this (depending on the instances you have requested)

[Note that you can consider using the MSDN subscriber benefits for deploying in Azure if you are an MSDN member - http://www.microsoft.com/windowsazure/msdn-benefits/]

image

WCF client :

So once you have deployed your WCF service in Azure, you need to create the Metro client to connect to this service. You will use the Add Service Reference (ASR) functionality for this. There is no difference from what I have showed in my previous post – you just pass the reference to your deployed Azure WCF service while generating the service reference – e.g. I used the reference - https://piyushjoweatherservice.cloudapp.net/WeatherService.svc to my Azure deployed service. 

[Note that this service is no longer running in Azure Smile so you will have to point the sample code to your own deployment]

Interesting parts of the generated service reference are the GetEndpointAddress method which references the Azure WCF service:

Code Snippet
  1. private static System.ServiceModel.EndpointAddress GetEndpointAddress(EndpointConfiguration endpointConfiguration) {
  2.             if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_IWeatherInfo)) {
  3.                 return new System.ServiceModel.EndpointAddress("https://piyushjoweatherservice.cloudapp.net/WeatherService.svc");
  4.             }
  5.             throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
  6.         }

and the GetBindingForEndpoint method which is configuring the TransportWithMessageCredential security mode on the binding

Code Snippet
  1. private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration) {
  2.             if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_IWeatherInfo)) {
  3.                 System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
  4.                 result.AllowCookies = true;
  5.                 result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.TransportWithMessageCredential;
  6.                 return result;
  7.             }
  8.             throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
  9.         }

Note that you don’t have to change anything in the generated service reference. ASR functionality will generate the correct service reference for you.

And that’s it – you are ready to consume your WCF service. The metro client code looks like the following:

Code Snippet
  1. private async void Button_Click(object sender, RoutedEventArgs e)
  2. {
  3.     AzureWeatherSvcRef.WeatherInfoClient proxy
  4.         = new AzureWeatherSvcRef.WeatherInfoClient();
  5.  
  6.     proxy.ClientCredentials.UserName.UserName = "myAzureUsername";
  7.     proxy.ClientCredentials.UserName.Password = "myAzurePassword";
  8.  
  9.     AzureWeatherSvcRef.WeatherInfo info = await proxy.GetWeatherInfoAsync(inputZip.Text);
  10.     WeatherReasults.Text = String.Format("{0} - {1}", info.Locality, info.WeatherDescription);
  11.     MapImage.Source = new BitmapImage(new Uri(info.MapImageUri));
  12.     WeatherImage.Source = new BitmapImage(new Uri(info.WeatherImageUri));
  13. }

Here I am creating a proxy to my WCF service in line 3, attaching the credentials recognized by my Azure deployed WCF service in line 6 and calling the service in line 9. As you would have gathered – considering this is a metro client application, we absolutely do not want to block the UI thread while making this call – and so we are calling the service asynchronously (note the async keyword on the button click event handler and the await keyword while making the call). Once the service returns results and populates the WeatherInfo object, I am using it to assign values to my various UI elements.

And that was that! Let me know if any part of this walkthrough needs any further clarification and I’ll add to that.

Thanks.