Using Azure API Management between client and Azure Mobile Services backend

I’m working on a solution with a customer which requires placing Azure API Management (APIM) between the mobile devices and the published Azure Mobile Services (ZuMo) .net backend.

Conceptually this is fairly straight forward, given that all of the Mobile Services capabilities are exposed as Web APIs but I needed to figure out what changes might be required to the client app to support that and prove that it works.

To get started, I created an API in Azure API Management with the relevant operations in APIM (for now I focused on the default GET request for the ToDoItem table so I defined a simple GET operation in APIM with the URL template /tables/TodoItem?$filter={filter}

image

The generated windows 8 app code for the ToDo item sample includes the following code to create the MobileServiceClient instance, which points at the ZuMo URL –

        public static MobileServiceClient MobileService = new MobileServiceClient(
            "https://travelviewer.azure-mobile.net/",
            "hmptBIjrEnAELyOgmmYPRPSOZlLpdo56"
        );

Naturally, to hit APIM instead of ZuMo directly, this needed to be updated to point at the APIM API published, in my case  I changed it to be

        public static MobileServiceClient MobileService = new MobileServiceClient(
            "https://apiyd.azure-api.net/travelviewer/",
            "hmptBIjrEnAELyOgmmYPRPSOZlLpdo56"
            );

Running the application with only this change was clearly not enough, I got the following error when trying to retrieve the ToDo items from the backend (currently configured to require no authentication)

image

This was not unexpected, but I wanted to prove the point. Trusted Fiddler provided more information – I could see the request going exactly as expected –

GET https://apiyd.azure-api.net/travelviewer/tables/TodoItem?$filter=(complete%20eq%20false) HTTP/1.1

and it included the various ZUMO headers (Installation Id, application, etc.

But the response was – HTTP/1.1 401 Access Denied

With the body providing the exact details –

{ 
   "statusCode": 401, 
   "message": "Access denied due to missing subscription key. 
               Make sure to include subscription key when making 
               requests to an API." 
}

Authentication to Azure API Management (APIM) is done by providing a subscription key either as a query string parameter (‘subscription-key’) or an HTTP header (‘ocp-apim-subscription-key’) and clearly the ZuMo client does not know it needs to do that, so – how do we work around that?

The answer, I believe, is to create an HttpMessageHandler or – more specifically – a DelegatingHandler.

The MobileServiceClient takes in a third parameter which is an array of such delegates that are then given the chance to process the outgoing requests and responses flowing through the client, this is a great opportunity to inject the missing HTTP header in a central place without affecting the application’s code.

and so I created a class that inherits from System.Net.Http.DelegatingHandler

class InsertAPIMHeader : DelegatingHandler
    {
    }

and I’ve overridden the main method – ‘SendAsync’ – and in it simply added the required header to the HttpRequest (in my case – hardcoded)

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                                    System.Threading.CancellationToken cancellationToken)  
{ request.Headers.Add("ocp-apim-subscription-key", "84095a7d792a47738464faae6bf950d3"); return base.SendAsync(request, cancellationToken); }

The last step is to write that into the MobileServiceClient Constructor, in my App’s App.xaml.cs I’ve added an instance of the delegate as the last parameter

public static MobileServiceClient MobileService = new MobileServiceClient(
            "https://apiyd.azure-api.net/travelviewer/",
            "hmptBIjrEnAELyOgmmYPRPSOZlLpdo56",
            new InsertAPIMHeader()
            );

 

Running the app again and refreshing the list of ToDo items now works. inspecting the request in Fiddler shows the request now has the APIM subscription key header

GET https://apiyd.azure-api.net/travelviewer/tables/TodoItem?$filter=(complete%20eq%20false) HTTP/1.1
X-ZUMO-FEATURES: TT,TC
X-ZUMO-INSTALLATION-ID: 226d6ea7-2979-4653-96d4-a230128719c5
X-ZUMO-APPLICATION: hmptBIjrEnAELyOgmmYPRPSOZlLpdo56
Accept: application/json
User-Agent: ZUMO/1.2 (lang=Managed; os=Windows Store; os_version=--; arch=Neutral; version=1.2.21001.0)
X-ZUMO-VERSION: ZUMO/1.2 (lang=Managed; os=Windows Store; os_version=--; arch=Neutral; version=1.2.21001.0)
ocp-apim-subscription-key: 84095a7d792a47738464faae6bf950d3
Host: apiyd.azure-api.net
Accept-Encoding: gzip

and, importantly – I actually got a result, meaning that APIM accepted the request, forwarded it to the mobile services backend and relayed the result. Success!

About Yossi Dahan
I work as a cloud solutions architect in the Azure team at Microsoft UK. I spend my days working with customers helping be successful in the cloud with Microsoft Azure.

Leave a comment