Gaurav Mantri's Personal Blog.

Windows Azure Media Service-Part II (Setup, API and Access Token)

In the previous post about Windows Azure Media Service (Media Service), I provided an introduction to the service as to how I understood it. I also explained some key terms associated with Media Service. You can read this post here: https://gauravmantri.com/2012/10/05/windows-azure-media-service-part-i-introduction/

In this post, we’ll talk about creating a media service through Windows Azure Portal, explore a bit of API & SDK and what options are available to you when it comes to develop and manage media applications using Media Service. We’ll also talk briefly about authentication/authorization and finally we’ll wrap this post with some code for writing our own library for managing Media Service.

Setup

Before you start building media applications using Media Service, first thing you would need to do is create a media service. You can create a new media service through Windows Azure Portal. Following screenshots demonstrate the steps for the same.

1. Provide media service name & choose a storage account

image 

First thing you would need to do is provide a media service name and choose a storage account where files related to various assets will be stored.

image

2. Manage access keys

Once media service has been created successfully, next thing you would want is to get hold of the access keys. If you have used Windows Azure Storage Service, you would be familiar with the concept of access keys. Essentially these are the keys required for securely communicating with Media Service. Anybody with access to these keys (and your service name) has complete access to your media service thus extreme care must be taken to protect these keys.

image

Another thing to notice here is the “Storage key configuration” section. While creating a media service, you specified which storage account you wish to use to store files. By choosing between “sync primary key” and “sync secondary key”, you are telling Media Service to use that particular key when communicating with the storage account. Also if you end up regenerating your storage account key (for whatever reason), by doing this you’re ensuring that your media service keeps working. I believe what it does is that it constantly polls storage service and fetches the storage account key you chose to keep in sync (total guess!!!)

Based on my testing if I don’t click on any of these “sync primary key” and “sync secondary key” buttons by default Media Service make use of storage account primary key. If I change my primary key, any operation I perform which involves Media Service to interact with this storage account will fail.

API & SDK

At the core of it, Media Service exposes management functionality through a REST API. It also provides a .Net SDK which essentially is a wrapper around REST API.

One may ask the question as to which route to go: REST API or .Net SDK? In my opinion, the answer depends on a number of factors, such as:

  • Flexibility: Usually in my experience, consuming REST API gives you more flexibility as you are not bound by only the functionality exposed through SDK.
  • Convenience: Obviously SDK provides you more convenience as most of the work as far as implementing REST API has already been done for you. Plus it includes some helper functionality (like moving files into blob storage) which is not there in REST API for Media Service.
  • Platform Feature Compatibility: In my experience, SDK comes a bit after (sometimes long after) REST API. If we take Windows Azure Storage for example, there are still some things you could not do with SDK (version 1.7 at the time of writing) while they are available in the system and are exposed via REST API. If we look at Media Service in particular, the ability to create Job Templates and Task Templates are still not available through SDK at the time of writing this blog. Thus if you need these functionality, you would have to go REST API route.
  • SDK Unavailability: Sometimes you don’t have a choice. For example, if you’re building functionality in say PHP and we know that currently there’s no SDK available for PHP. In that case you would need to use REST API. Having said this thing and given the way things are going in other parts of Windows Azure, I would not be surprised if the SDK for many common platforms (PHP, Java, node.js) arrive pretty soon.

REST API

A few things about REST API:

  • Get an access token first: Before using REST API, you would need to get an access token first from Windows Azure Access Control Service (ACS). This is described in detail later in this blog post.
  • Know about various request/response headers: Again when using REST API, understand about various headers you would need to pass in your request and the headers returned in response. You can find more information about this here: http://msdn.microsoft.com/en-us/library/windowsazure/hh973616.aspx.

.Net SDK

A thing or two I noticed about .Net SDK:

  • Windows Azure Storage Client Library Version: Please note that at the time of writing this blog, the SDK has a dependency on Windows Azure Storage Client Library for SDK version 1.6 (library version 1.1) while the most latest SDK version is 1.7. Please make a note of that.

Authenticating (or is it Authorizing Smile) REST API Requests

As mentioned above, before you could invoke Media Service REST API functionality you would need to get an access token from Windows Azure Access Control Service (ACS). In order to do so, a few things to keep in mind:

Endpoint:

Endpoint for getting an access token is: https://wamsprodglobal001acs.accesscontrol.windows.net/v2/OAuth2-13

HTTP Method:

HTTP Method for this request is POST.

Request Body:

Request body should be in this format:


grant_type=client_credentials&client_id=[client id value]&client_secret=[URL-encoded client secret value]&scope=urn%3aWindowsAzureMediaServices

For example, if we take the values from above, the request body will be:


grant_type=client_credentials&client_id=gauravdemomediaservice&client_secret=RlT8voLHr6aHNYyxNOxS%2f1MkRsgT5Tb8m9guPMucsfw%3d&scope=urn%3aWindowsAzureMediaServices

Response Body:

Response is returned in JSON format. Here’s how typical response looks like:

{ 
    "token_type":"http://schemas.xmlsoap.org/ws/2009/11/swt-token-profile-1.0", 
    "access_token":"http%3a%2f%2fschemas.xmlsoap.org%2fws%2f2005%2f05%2fidentity%2fclaims%2fnameidentifier=gauravdemomediaservice&urn%3aSubscriptionId=35d2de3b-a2cd-4160-aee5-f55d799962c4&http%3a%2f%2fschemas.microsoft.com%2faccesscontrolservice%2f2010%2f07%2fclaims%2fidentityprovider=https%3a%2f%2fwamsprodglobal001acs.accesscontrol.windows.net%2f&Audience=urn%3aWindowsAzureMediaServices&ExpiresOn=1349691469&Issuer=https%3a%2f%2fwamsprodglobal001acs.accesscontrol.windows.net%2f&HMACSHA256=LrliUJEEfUlBPTJJVlp35%1fS2XEX7xwWUQRN%2fb1NkJkM%3d", 
    "expires_in":"5999", 
    "scope":"urn:WindowsAzureMediaServices" 
}

A few things to keep in mind here:

  • access_token: This is the access token you would need when working with Media Service REST API. It must be included in every request.
  • expires_in: This indicates the number of seconds for which the access token is valid. One must keep an eye on this value and ensure that the access token has not expired. One needs to get the access token again if the access token has expired.

Sample Project

Now what we will do is create a simple class library project which would be the wrapper around REST API much like .Net SDK. Then we’ll start consuming this library in another project. We’ll use VS 2010 to create this project and make use of .Net framework version 4.0. For the sake of simplicity, we’ll call this project as “WAMSRestWrapper”. Also because this REST API sends and receives the data in JSON format, we’ll make use of Json.Net library.

Since I’ll also be learning the REST API, the code would not be the best quality code and would desire a lot of improvements. Please feel free to make improvements as you see fit.

image

image

In this blog post, only thing we will do is get the access token and store it with our application.

To do so, let’s first create a class called AcsToken. Members of this class will map to the JSON data returned by ACS.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WAMSRestWrapper
{
    public class AcsToken
    {
        public string token_type
        {
            get;
            set;
        }

        public string access_token
        {
            get;
            set;
        }

        public int expires_in
        {
            get;
            set;
        }

        public string scope
        {
            get;
            set;
        }
    }
}

Next let’s create a class for fetching this ACS token. Since this class will be doing a lot of stuff in the days to come, let’s call it “MediaServiceContext” (inspired by MediaContextBase in .Net SDK) Smile.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Web;
using Newtonsoft.Json;
using System.Globalization;
using System.IO;

namespace WAMSRestWrapper
{
    public class MediaServiceContext
    {
        private const string acsEndpoint = "https://wamsprodglobal001acs.accesscontrol.windows.net/v2/OAuth2-13";

        private const string acsRequestBodyFormat = "grant_type=client_credentials&client_id={0}&client_secret={1}&scope=urn%3aWindowsAzureMediaServices";

        private string _accountName;

        private string _accountKey;

        private string _accessToken;

        private DateTime _accessTokenExpiry;

        /// <summary>
        /// Creates a new instance of <see cref="MediaServiceContext"/>
        /// </summary>
        /// <param name="accountName">
        /// Media service account name.
        /// </param>
        /// <param name="accountKey">
        /// Media service account key.
        /// </param>
        public MediaServiceContext(string accountName, string accountKey)
        {
            this._accountName = accountName;
            this._accountKey = accountKey;
        }

        /// <summary>
        /// Gets the access token. If access token is not yet fetched or the access token has expired,
        /// it gets a new access token.
        /// </summary>
        public string AccessToken
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_accessToken) || _accessTokenExpiry < DateTime.UtcNow)
                {
                    var tuple = FetchAccessToken();
                    _accessToken = tuple.Item1;
                    _accessTokenExpiry = tuple.Item2;
                }
                return _accessToken;
            }
        }

        /// <summary>
        /// This function makes the web request and gets the access token.
        /// </summary>
        /// <returns>
        /// <see cref="System.Tuple"/> containing 2 items - 
        /// 1. The access token. 
        /// 2. Token expiry date/time.
        /// </returns>
        private Tuple<string, DateTime> FetchAccessToken()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(acsEndpoint);
            request.Method = "POST";
            string requestBody = string.Format(CultureInfo.InvariantCulture, acsRequestBodyFormat, _accountName, HttpUtility.UrlEncode(_accountKey));
            request.ContentLength = Encoding.UTF8.GetByteCount(requestBody);
            request.ContentType = "application/x-www-form-urlencoded";
            using (StreamWriter streamWriter = new StreamWriter(request.GetRequestStream()))
            {
                streamWriter.Write(requestBody);
            }
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                using (StreamReader streamReader = new StreamReader(response.GetResponseStream(), true))
                {
                    var returnBody = streamReader.ReadToEnd();
                    var acsToken = JsonConvert.DeserializeObject<AcsToken>(returnBody);
                    return new Tuple<string, DateTime>(acsToken.access_token, DateTime.UtcNow.AddSeconds(acsToken.expires_in));
                }
            }
        }
    }
}

The code is pretty straight forward. The constructor takes 2 parameters – account name and key and it exposes a public property called AccessToken. If an access token has never been fetched in this object’s lifecycle or has expired, a web request is made to ACS and token is fetched.

Now let’s write a simple console application which makes use of this library and all it does is prints out the access token on the console.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WAMSRestWrapper;
using Microsoft.WindowsAzure.MediaServices.Client;

namespace WAMSSampleApplication
{
    class Program
    {
        static string accountName = "<your media service account name>";
        static string accountKey = "<your media service account key>";
        static MediaServiceContext context;
        static void Main(string[] args)
        {
            context = GetContext();
            var accessToken = context.AccessToken;
            Console.WriteLine("Acces token fetched: " + accessToken);
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("Press any key to terminate the application!");
            Console.ReadLine();
        }

        static MediaServiceContext GetContext()
        {
            return new MediaServiceContext(accountName, accountKey);
        }
    }
}


Once we run this program, this is what we see on the console.

image

Now when invoking the Media Service REST API, we will make use of this access token.

Summary

That’s it for this post. In the next post, we will deal with more REST API functionality and expand this library. I hope you have found this information useful. As always, if you find some issues with this blog post please let me know immediately and I will fix them ASAP.

So long and stay tuned!


[This is the latest product I'm working on]