Making HTTP calls in WinRT with C++

January 14, 2013

When working with Windows Store applications (“metro”), it’s sometimes necessary to make HTTP calls. one classic example is to register for push notifications. After obtaining a unique channel URI, the app needs to send that URI to its application server, as that particular URI is the one to use by the application server to execute a push notification against the Windows Notification Service (WNS).

Getting the channel URI is fairly simple, with a call to the static PushNotificationChannelManager::CreatePushNotificationChannelForApplicationAsync
method. Now comes the tricky part: how to send the resulting URI to the application server?

In .NET, things are relatively easy. Just use the HttpClient class (introduced in .NET 4.5) for sending HTTP requests. It provides an easy to use asynchronous model that can be leveraged in C# using the await keyword, but it’s part of .NET, not WinRT. What about C++ or C++/CX?

Let’s take a concrete example: suppose we have a WCF service that is hosted in our application server, that exposes a method to register for push notifications:

[DataContract(Namespace="")]

public class ClientInfo {

    [DataMember]

    public string Uri { get; set; }

    [DataMember]

    public string ClientID { get; set; }

}

 

[ServiceContract]

public interface IMovieService {

    [OperationContract, WebInvoke(UriTemplate="register")]

    void RegisterForPushNotification(ClientInfo info);

}

To make things easier, we’ll expose the service in a RESTful way. This will make creating the actual HTTP messages a lot easier. Actually, with .NET it’s not such a big deal to work with SOAP based services. Just use the “Add Service Reference…” option in Visual Studio, and an appropriate client proxy is generated for you. Unfortunately, this is unavailable for C++, so the first step is to make the required messages simpler by using REST.

Just for the sake of completeness, WCF REST support requires using the WebHttpBinding and the WebHttp behavior. The simplest way to get these is by using the WebServiceHost class. For WCF services that are hosted in IIS, the factory should be replaced with WebServiceHostFactory to get IIS to use the correct host:

<%@ ServiceHost Language="C#" Debug="true" Service="MoviesWorld.MovieService" 

CodeBehind="MovieService.svc.cs" 

Factory= "System.ServiceModel.Activation.WebServiceHostFactory" %>

Now that the server is set up, how would we call it from a C++ Windows Store application?

The Windows Runtime, unfortunately, does not provide a class that is capable of sending HTTP requests (similar to .NET HttpCient) The official recommendation is to use the classic XMLHttpRequest COM object (exposed through appropriate COM interfaces), but this is not easy to do, especially in an asynchronous way – a COM object must be written to implement a callback interface, and other such unpleasant details.

Fortunately, one of the Windows 8 samples provided by Microsoft has a nice helper class named HttpRequest (a regular C++ class, not a WinRT class) that wraps all that unpleasantness for us. We can use this class to send GET and POST HTTP requests. For example, to register the client app for push notifications, we can use the following code:

create_task(PushNotificationChannelManager::CreatePushNotificationChannelForApplicationAsync()).then(

    [this](PushNotificationChannel^ channel) {

    HttpRequest request;

    wstring body = wstring(L"<ClientInfo><ClientID>123</ClientID><Uri>") + channel->Uri->Data() + L"</Uri></ClientInfo>";

 

    return request.PostAsync(ref new Uri("http://MyServerURL/MovieService.svc/register"), L"text/xml", body);

}).then([](wstring response) {

});

First, we get a unique channel URI from the Windows Notification Service (WNS), and that channel URI (along with come client ID) should be sent to the application server. concurrency::create_task is used to create a task representing the asynchronous call, with the then clause handling completion (that’s the best we currently can do with C++/CX; compare this to using the C# await keyword – C++ still has a way to go). Then we build a plain XML string with the channel URI (and some dummy client ID) and call HttpRequest::PostAsync to make the HTTP request (I actually modified HttpRequest slightly to allow PostAsync to accept a content type (text/xml in this case), as well as the message body).

That’s it. Not as easy as C#, but not too difficult either.

Hopefully, future versions of WinRT will provide classes within WinRT that are easy to use for HTTP calls, as these are fairy common these days.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*