WCF in Windows 8 Metro styled apps? Absolutely supported


[Updated for Win8/Dev11 Beta]

Hi all,
With Windows 8 metro styled applications getting a great buzz – I thought this was a perfect time to introduce the WCF support for Metro applications.

We provide support for WCF client inside a Metro application with a subset of features compared to classic desktop applications. See here – http://blogs.msdn.com/b/piyushjo/archive/2011/10/19/wcf-for-metro-apps-supported-functionality.aspx for the supported feature list. This enables you to consume all those awesome web services out there, in your metro app very easily and as we will see – very similar to what you are already used to.

We will start with a simple Metro application in C# and consume an ASMX web service (one of the first weather services I found in my search results). The application in its current form will be a simple weather reporting client taking in a US zip code and displaying the weather by calling an external web service hosted here – http://wsf.cdyne.com/WeatherWS/Weather.asmx.  The point of the demo is to clarify the client experience for Win8 Metro app.
In future blog posts, we will extend the application to include more of supported WCF features and will consume WCF services which is likely going to be the norm.

image

1. Open Visual Studio 11 and create a new Windows Metro style Blank application.

image

2. In your application – right click on References and add the service reference to http://wsf.cdyne.com/WeatherWS/Weather.asmx service just as you do for classic desktop apps. This will generate a service reference to this weather service.

image

3. So far nothing out of the ordinary – everything is exactly the same as what we are used to while adding a service reference to a web service.

The fun starts now:
a) First note that there is no configuration file generated. Metro apps do not support the traditional xml styled application so we have modified our Add Service Reference (ASR) experience from within a metro app to generate code based configuration.
Where will you find this generated code? Go to the Reference.cs file generated under the service reference folder. You will have to click "Show All Files" in Solution explorer.
You will see code like the following for the generated binding and endpoint address:

    

Code Snippet
  1. private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration) {
  2.     if ((endpointConfiguration == EndpointConfiguration.WeatherSoap)) {
  3.         System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
  4.         result.MaxBufferSize = int.MaxValue;
  5.         result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
  6.         result.MaxReceivedMessageSize = int.MaxValue;
  7.         result.AllowCookies = true;
  8.         return result;
  9.     }
  10.     throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
  11. }
  12. private static System.ServiceModel.EndpointAddress GetEndpointAddress(EndpointConfiguration endpointConfiguration) {
  13.     if ((endpointConfiguration == EndpointConfiguration.WeatherSoap)) {
  14.         return new System.ServiceModel.EndpointAddress("http://wsf.cdyne.com/WeatherWS/Weather.asmx");
  15.     }
  16.     throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
  17. }

Now this also means that if you need to change any binding properties on the client side – you need to do this in code. You can use the newly generated partial method ‘ConfigureEndpoint’ to implement any changes outside the generated proxy class so that you can update the generated proxy (including Reference.cs) without any fear of your changes being overwritten.

Code Snippet
  1. public partial class WeatherSoapClient : System.ServiceModel.ClientBase<MetroTestApp.WeatherService.WeatherSoap>, MetroTestApp.WeatherService.WeatherSoap {
  2.         
  3.         /// <summary>
  4.         /// Implement this partial method to configure the service endpoint.
  5.         /// </summary>
  6.         /// <param name="serviceEndpoint">The endpoint to configure</param>
  7.         /// <param name="clientCredentials">The client credentials</param>
  8.         static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);

b) Next – you will also notice a difference in the style of operations generated for the service.
Note that you only have task based async patterned methods generated. This ensures that there are no blocking calls from the metro styled UI apps, even unknowingly.
If you will generate a similar service reference from a classic desktop app in Dev11 – you will see both synchronous and task based async methods. Task based async pattern is the recommended pattern for doing async programming going forward therefore in Add Service Reference – Advanced dialog, we select it for you by default:

image

 

4) That’s it. Thereafter you can call the service asyn using the following Task based async model:

Code Snippet
  1. private async void GoButton_Click(object sender, RoutedEventArgs e)
  2. {
  3.     WeatherSoapClient proxy = new WeatherSoapClient();
  4.     WeatherReturn result = await proxy.GetCityWeatherByZIPAsync(inputZipCode.Text);
  5.     if (result.Success)
  6.     {
  7.         resultCityState.Text = String.Format("{0}, {1}", result.City, result.State);
  8.         resultDetails.Text = String.Format
  9.             ("\nConditions – {0} \nTemperature – {1}F \nRelative Humidity – {2} \nWind – {3} \nPressure – {4}",
  10.             result.Description, result.Temperature, result.RelativeHumidity, result.Wind, result.Pressure);
  11.     }
  12.     else
  13.     {
  14.         resultCityState.Text = "City not found";
  15.     }
  16. }

 

Note that the method is marked async and we are making the service call with the await keyword.
5) You don’t have to provide any additional capability and the default capability Internet (Client) is sufficient.
image
So that was pretty much it! For you – while developing metro apps – you just need to be aware that:

1) You need to make all configuration in code.
2) You need to make all service calls async using the task based pattern.

Attached is a sample app which contains two projects – one is a metro styled app and another a regular console app making the same service call. You can compare the generated service references to get more insight.

Sample code attached. 

Thanks!

MetroTestApp.zip

Comments (6)

  1. Thanks Piyush!

    You answered a lot of questions I had about WCF in Metro apps – a really helpful article 🙂

    And I was able to get your example working without any problems!

    If you have any background information, I'm interested to know why the decision was made to go with code-based configuration, as opposed to XML-based configuration. Both have advantages and disadvantages. Just curious…

    Thanks again – hopefully you'll be able to post some more articles.

    Russell

  2. Russell,

    Config's purpose is typically to enable changing application settings/ other parameters without recompiling. However for metro styled applications, once a developer has developed an application and crated a package and published it to marketplace, it is unlikely that customers who download and install this metro app package will want to do anything via xml configuration.

    Thanks.

  3. Saso says:

    Hi Piyush,

    Great post…

    I am however having trouble connecting to Exchange Online. The link to the EWS (as returned by autodiscovery) is: db3prd0104.outlook.com/…/Exchange.asmx

    When I try to add a new Service Reference, the service is found, I can click "OK" and a service reference (Namespace = ExchangeTest) is created.

    The messages.xsd and types.xsd files are both created as well. But the Reference.cs file (below Reference.svcmap) is empty.

    Any ideas?

  4. Hi Saso,

    Exchange ASMX web services not generating any service reference is a known issue and we are tracking it. In general, there are some inconsistencies in the generated service reference in the preview build and we are working to fix it.

    Thanks.

  5. Saso says:

    Thanks a lot for the reply…

    Any ideas on how to go around that? Any examples on how to manually implement those web services?

  6. Hi Saso,

    The only way I know right now is to generate the proxy in a console application which will show up all the sync & async methods. You then need to remove the sync methods as only async methods are supported. You also need to manually add a couple of additional methods for the binding and endpoint address – you can find them in my sample post. I'll try to publish a sample for this next week.

    Thanks.