Gaurav Mantri's Personal Blog.

Windows Azure Media Service-Part III (Managing Assets via REST API)

UPDATE: I originally posted this blog in October 2012. At that time the REST API service version was 1.0. A few days back, Media Services team released a new version of REST API (version 2.0). There are some changes in version 2.0 over version 1.0 so I decided to update this blog post.

In the last post about Windows Azure Media Service (Media Service), I talked about setup, a little bit of API and how to get access token from Windows Azure Access Control Service (ACS). You can read that post here: https://gauravmantri.com/2012/10/08/windows-azure-media-service-part-ii-setup-api-and-access-token/.

In this post, I’ll talk about managing assets from REST API point of view. However before we do that, first we need to know how to connect to media service. So let’s start!


Connecting to the Media Service

Default URI for connecting to media service is https://media.windows.net/. When implementing REST wrapper, we would need to first connect to this URI to find out if Media Service is redirecting us to a new URI or not. This can be identified by checking the response status. If we get a response status code of 301 (Moved Permanently), we should fetch the new URI from the “Location” response header and use that for subsequent requests.

Based on this, let’s look at the modified code for MediaServiceContext class. I’m including only the new changes I made for this purpose.


        private string _wamsEndpoint = "https://media.windows.net/";

        /// <summary>
        /// Gets the endpoint for making REST API calls.
        /// </summary>
        public string WamsEndpoint
        {
            get
            {
                return _wamsEndpoint;
            }
        }

        /// <summary>
        /// This function checks if we need to redirect all Media Service requests.
        /// </summary>
        public void CheckForRedirection()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(WamsEndpoint);
            request.AllowAutoRedirect = false;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, AccessToken));
            request.Method = HttpVerbs.Get;

            using (var response = (HttpWebResponse)request.GetResponse())
            {
                if (response.StatusCode == HttpStatusCode.Moved || response.StatusCode == HttpStatusCode.MovedPermanently)
                {
                    string newLocation = response.Headers["Location"];
                    if (!newLocation.Equals(_wamsEndpoint))
                    {
                        _wamsEndpoint = newLocation;
                        _accessToken = string.Empty;//So that we can force to get a new access token.
                        _accessTokenExpiry = DateTime.MinValue;
                    }
                }
            }
        }

If you notice, if we find the requests are redirected to another URI, we’re resetting the “_accessToken” variable. This is done so that we will re-fetch the access token now that we’re using a new URI. Another thing you will notice in the code above is the we’re forcing the request to not auto-redirect to the new URI. This is important because based on the documentation, HTTP verbs and request bodies will not be forwarded to the new URI.

So the process would be:

  1. Create an instance of MediaServiceContext class.
  2. Fetch access token.
  3. Check if we need to use a new URI instead of default URI.

To read more about this, please visit MSDN documentation here: http://msdn.microsoft.com/en-us/library/windowsazure/jj129576.aspx.

JSON or XML?

How about both? Bless the Media Service team for this Smile. Here’s an interesting thing I found. Unlike other Windows Azure Services REST API (like Storage and Service Management) where XML is the only way to send and receive the management data, Media Service REST API actually supports both JSON and XML. I knew about JSON because REST API documentation talks about that. However I accidently found out that it supports XML as well (AtomPUB format). In fact the SDK communicates with the REST API in XML data format.

You need to tell REST API about the format in which you’re sending the data. You can do so by specifying the "content-type" of the request. For example:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
//Sending the data in JSON format.
request.ContentType = "application/json;odata=verbose";
//Sending the data in XML format.
request.ContentType = "application/atom+xml";

Similarly, you need to tell REST API about the format in which you wish to receive the data. You can do so by specifying the "Accept" property of the request. For example:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
//Sending the data in JSON format.
request.Accept = "application/json;odata=verbose";
//Sending the data in XML format.
request.Accept = "application/atom+xml,application/xml";

Since I want to learn JSON, we’re going to focus on that in this series.

Managing Assets

Now let’s get back to topic at hand i.e. managing assets Smile.

Definition

An asset can be defined as a logical entity which contains information about media. It may contain one more files (audio, video etc.) which needs to be processed.

Asset Entity

An asset entity defines the abstract concept of an asset in Media Service. You can read about the attributes of an asset entity here on MSDN: http://msdn.microsoft.com/en-us/library/windowsazure/hh974277.aspx#asset_entity_properties.

Based on this, we’ll create our own class. Let’s call it Asset. Here’s the code for that:

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

namespace WAMSRestWrapper
{
    /// <summary>
    /// Class representing an asset in a media service
    /// </summary>
    public class Asset
    {
        private readonly MediaServiceContext _context;

        /// <summary>
        /// Creates an instance of <see cref="Asset"/>
        /// </summary>
        /// <param name="context">
        /// <see cref="MediaServiceContext"/>
        /// </param>
        internal Asset(MediaServiceContext context)
        {
            _context = context;
        }

        /// <summary>
        /// Creates an instance of <see cref="Asset"/>
        /// </summary>
        /// <param name="context">
        /// <see cref="MediaServiceContext"/>
        /// </param>
        /// <param name="id">
        /// Asset id
        /// </param>
        internal Asset(MediaServiceContext context, string id)
            : this(context)
        {
            Id = id;
        }

        /// <summary>
        /// Asset id.
        /// </summary>
        public string Id
        {
            get;
            internal set;
        }

        /// <summary>
        /// Asset state - Initialized (0), Deleted (1) [In Version 2.0, "Published" state is deprecated]   
        /// </summary>
        public AssetState State
        {
            get;
            set;
        }

        /// <summary>
        /// Date/time asset is created.
        /// </summary>
        public DateTime Created
        {
            get;
            internal set;
        }

        /// <summary>
        /// Date/time asset was last modified.
        /// </summary>
        public DateTime LastModified
        {
            get;
            internal set;
        }

        /// <summary>
        /// Alternate id for asset.
        /// </summary>
        public string AlternateId
        {
            get;
            set;
        }

        /// <summary>
        /// Friendly name for asset.
        /// </summary>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Encryption options for asset - None (0), StorageEncrypted (1), CommonEncryptionProtected (2)
        /// </summary>
        public AssetEncryptionOption Options
        {
            get;
            set;
        }

    }

    /// <summary>
    /// Enumeration indicating asset state.
    /// Please note that version 2.0, Publish Asset action is deprecated. Hence it is removed from here.
    /// </summary>
    public enum AssetState
    {
        Initialized = 0,
        //Published = 1,
        Deleted = 1,
    }

    /// <summary>
    /// Enumeration for asset encryption options.
    /// </summary>
    public enum AssetEncryptionOption
    {
        None = 0,
        StorageEncrypted = 1,
        CommonEncryptionProtected = 2,
    }
}

Operations

REST API allows you to perform following operations on an asset:

  • Create
  • Delete
  • Update
  • Publish (As of version 2.0, this operation is now deprecated)
  • List
    Rest of the blog post will be focused on these operations and we’ll write some code to implement these operations.

Create

As the name suggests, this operation creates a new asset in Media Service for a given media service. A few things to consider here:

Endpoint https://media.windows.net/Assets

OR

the URI received when we checked for redirection (see "Connecting to the Media Service" section above) and append “Assets” to that.
HTTP Method POST
Request Headers DataServiceVersion

MaxDataServiceVersion

x-ms-version

Authorization
Request Content Type application/json;odata=verbose
Accept application/json;odata=verbose
Request Body Format {

    "Name": "<Asset Name>",

    "State": "0",

    "Options":"<Asset encryption option (as Integer)",

    "Created":"<Asset creation date in yyyy-MM-ddT00:00:00 format>",

    "LastModified":"<Asset last modified date in yyyy-MM-ddT00:00:00 format>"

}

e.g.

{

    "Name": "Test Asset",

    "State": "0",

    "Options":"0",

    "Created":"0001-01-01T000000",

    "LastModified":"0001-01-01T000000"

}

 

Here’s the code for creating an asset:

        /// <summary>
        /// Creates an asset
        /// </summary>
        public void Create()
        {
            if (string.IsNullOrWhiteSpace(Name))
            {
                Name = Guid.NewGuid().ToString();
            }

            string assetCreateRequestPayloadFormat = @"{0} ""Name"": ""{1}"", ""State"": ""{2}"", ""Options"":""{3}"", ""Created"":""{4}"", ""LastModified"":""{5}"" {6}";
            string requestBody = string.Format(CultureInfo.InvariantCulture, assetCreateRequestPayloadFormat, "{", Name, (int)State, (int)Options,
                Created.ToString("yyyy-MM-ddTHH:mm:ss"), LastModified.ToString("yyyy-MM-ddTHH:mm:ss"), "}");
            
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets/", _context.WamsEndpoint));
            request.Method = HttpVerbs.Post;
            request.ContentType = RequestContentType.Json;
            request.Accept = RequestContentType.Json;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, _context.AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            request.ContentLength = Encoding.UTF8.GetByteCount(requestBody);

            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();
                    JObject responseJsonObject = JObject.Parse(returnBody);
                    var d = responseJsonObject["d"];
                    Id = d.Value<string>("Id");
                    State = (AssetState)d.Value<int>("State");
                    Options = (AssetEncryptionOption)d.Value<int>("Options");
                    AlternateId = d.Value<string>("AlternateId");
                    Created = d.Value<DateTime>("Created");
                    LastModified = d.Value<DateTime>("LastModified");
                }
            }

        }

and the helper code for calling this function:

var asset = context.GetAssetReference();
asset.Name = "My 1st Media Service Asset";
asset.Create();

Delete

As the name suggests, this operation deletes an existing asset in Media Service for a given media service. A few things to consider here:

Endpoint https://media.windows.net/Assets(‘<assetid>’)  

OR

the URI received when we checked for redirection (see "Connecting to the Media Service" section above) and append “Assets(‘<assetid>’)” to that [Don’t forget to replace <assetid> with the actual asset id value Smile].
HTTP Method DELETE
Request Headers DataServiceVersion

MaxDataServiceVersion

x-ms-version

Authorization

 

Here’s the code for deleting an asset:

        /// <summary>
        /// Deletes the asset.
        /// </summary>
        public void Delete()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets('{1}')", _context.WamsEndpoint, Id));
            request.Method = HttpVerbs.Delete;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, _context.AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            var response = (HttpWebResponse)request.GetResponse();
        }

and the helper code for calling this function:

var assetId = "<asset id e.g. nb:cid:uuid:63b0ddd2-5784-4bc7-b9df-85785eaf57a1>";
var asset = context.GetAssetReference(assetId);
asset.Delete();

Please note that when an asset is deleted, all the files associated with that particular asset. If I understand the documentation correctly, one needs to delete locators and content keys associated with an asset before deleting it.

Update

This operation allows you to update some of the properties of an asset in Media Service for a given media service. Please note that not all properties of an asset can be updated. For example, none of the system defined properties like Created or LastModified etc. can be updated. Also Options properties can’t be updated as well.

A few things to consider here:

Endpoint https://media.windows.net/Assets(‘<assetid>’)

OR

the URI received when we checked for redirection (see "Connecting to the Media Service" section above) and append “Assets(‘<assetid>’)” to that [Don’t forget to replace <assetid> with the actual asset id value Smile].
HTTP Method MERGE
Request Headers DataServiceVersion

MaxDataServiceVersion

x-ms-version

Authorization
Request Content Type application/json;odata=verbose
Request Body Format {

"Name": "<New Asset Name>",

"AlternateId":"<Asset Alternate Id>"

}

e.g.

{

"Name": "New Test Asset",

"AlternateId":"An alternate id"

}

 

Here’s the code for updating an asset:


        /// <summary>
        /// Updates an asset
        /// </summary>
        public void Update()
        {
            string assetCreateRequestPayloadFormat = @"{0} ""Name"": ""{1}"", ""AlternateId"": ""{2}"" {3}";
            string requestBody = string.Format(CultureInfo.InvariantCulture, assetCreateRequestPayloadFormat, "{", Name, AlternateId, "}");

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets('{1}')", _context.WamsEndpoint, Id));
            request.Method = HttpVerbs.Merge;
            request.ContentType = RequestContentType.Json;
            request.Accept = RequestContentType.Json;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, _context.AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            request.ContentLength = Encoding.UTF8.GetByteCount(requestBody);

            using (StreamWriter streamWriter = new StreamWriter(request.GetRequestStream()))
            {
                streamWriter.Write(requestBody);
            }
            var response = (HttpWebResponse)request.GetResponse();
        }

and the helper code for calling this function:

var assetId = "<asset e.g. nb:cid:uuid:63b0ddd2-5784-4bc7-b9df-85785eaf57a1>";
var asset = context.GetAssetReference(assetId);
asset.Name = "new asset name";
asset.AlternateId = Guid.NewGuid().ToString();
asset.Update();

 

Publish

PLEASE NOTE: As of version 2.0, this operation is now deprecated.

This operation allows you to publish an asset. Publishing an asset means telling Media Service that this asset is ready to be processed. This should be the last step of “Ingestion” process after you have uploaded all the files associated with an asset and done all other things which are required. Once an asset is published, you can’t make any changes to that asset.

A few things to consider here:

Endpoint https://media.windows.net/Assets(‘<assetid>’)/Publish

OR

the URI received when we checked for redirection (see "Connecting to the Media Service" section above) and append “Assets(‘<assetid>’)/Publish” to that [Don’t forget to replace <assetid> with the actual asset id value Smile].
HTTP Method POST
Request Headers DataServiceVersion

MaxDataServiceVersion

x-ms-version

Authorization

Here’s the code for updating an asset:

        /// <summary>
        /// Publishes an asset
        /// </summary>
        public void Publish()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets('{1}')/Publish", _context.WamsEndpoint, Id));
            request.Method = HttpVerbs.Post;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, _context.AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            request.ContentLength = 0;
            var response = (HttpWebResponse)request.GetResponse();
        }
    }

and the helper code for calling this function:

var assetId = "<asset id e.g. nb:cid:uuid:63b0ddd2-5784-4bc7-b9df-85785eaf57a1>";
var asset = context.GetAssetReference(assetId);
asset.Publish();

Please ensure that the asset has at least one file uploaded otherwise the publish operation will fail.

List

As the name suggests, this operation fetches a list of assets associated with a media service. This function can also be used to fetch a single asset.

Listing All Assets:

Endpoint https://media.windows.net/Assets

OR

the URI received when we checked for redirection (see "Connecting to the Media Service" section above) and append “Assets”.
HTTP Method GET
Request Headers DataServiceVersion

MaxDataServiceVersion

x-ms-version

Authorization

Here’s the code for fetching the list of all assets.

        /// <summary>
        /// List all assets in a media service.
        /// </summary>
        /// <returns>
        /// </returns>
        public IEnumerable<Asset> ListAssets()
        {
            List<Asset> assets = new List<Asset>();
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets", WamsEndpoint));
            request.Accept = RequestContentType.Json;
            request.Method = HttpVerbs.Get;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                using (StreamReader streamReader = new StreamReader(response.GetResponseStream(), true))
                {
                    var returnBody = streamReader.ReadToEnd();
                    JObject responseJsonObject = JObject.Parse(returnBody);
                    var items = responseJsonObject["d"]["results"];
                    foreach (var d in items)
                    {
                        var Id = d.Value<string>("Id");
                        var State = (AssetState)d.Value<int>("State");
                        var Options = (AssetEncryptionOption)d.Value<int>("Options");
                        var AlternateId = d.Value<string>("AlternateId");
                        var Created = d.Value<DateTime>("Created");
                        var LastModified = d.Value<DateTime>("LastModified");
                        var Name = d.Value<string>("Name");
                        assets.Add(new Asset(this, Id)
                        {
                            Name = Name,
                            State = State,
                            Options = Options,
                            AlternateId = AlternateId,
                            Created = Created,
                            LastModified = LastModified,
                        });
                    }
                }
            }
            return assets;
        }

and the helper code for calling this function:

          
var assets = context.ListAssets();

Listing Single Asset:

Endpoint https://media.windows.net/Assets(‘<assetid>’)

OR

the URI received when we checked for redirection (see "Connecting to the Media Service" section above) and append “Assets(‘<assetid>’)” to that [Don’t forget to replace <assetid> with the actual asset id value Smile].
HTTP Method GET
Request Headers DataServiceVersion

MaxDataServiceVersion

x-ms-version

Authorization

Here’s the code for fetching information about a single asset.

        /// <summary>
        /// Gets information about an asset.
        /// </summary>
        public void Get()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets('{1}')", _context.WamsEndpoint, Id));
            request.Method = HttpVerbs.Get;
            request.Accept = RequestContentType.Json;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, _context.AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                using (StreamReader streamReader = new StreamReader(response.GetResponseStream(), true))
                {
                    var returnBody = streamReader.ReadToEnd();
                    JObject responseJsonObject = JObject.Parse(returnBody);
                    var d = responseJsonObject["d"];
                    Id = d.Value<string>("Id");
                    State = (AssetState)d.Value<int>("State");
                    Options = (AssetEncryptionOption)d.Value<int>("Options");
                    AlternateId = d.Value<string>("AlternateId");
                    Created = d.Value<DateTime>("Created");
                    LastModified = d.Value<DateTime>("LastModified");
                }
            }
        }
    }

and the helper code for calling this function:

var assetId = &quot;<asset e.g. nb:cid:uuid:63b0ddd2-5784-4bc7-b9df-85785eaf57a1>&quot;;
var asset = context.GetAssetReference(assetId);
asset.Get();

 

Wrapping Up

In this blog post, we learnt about the REST API for managing assets in Media Service. Here’s the complete source code for what we have done so far. As I said in my previous post, this is definitely not the best code and desires a lot of optimization / refactoring. Please feel free to modify the code to suit your need.

AcsToken.cs

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;
        }
    }
}

Constants.cs

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

namespace WAMSRestWrapper
{
    /// <summary>
    /// Values for various request headers
    /// </summary>
    internal static class RequestHeaderValues
    {
        /// <summary>
        /// DataServiceVersion request header (3.0)
        /// </summary>
        internal const string DataServiceVersion = "3.0";

        /// <summary>
        /// MaxDataServiceVersion request header (3.0)
        /// </summary>
        internal const string MaxDataServiceVersion = "3.0";

        /// <summary>
        /// x-ms-version request header (2.0)
        /// </summary>
        internal const string XMsVersion = "2.0";

        /// <summary>
        /// Authorization request header format
        /// </summary>
        internal const string Authorization = "Bearer {0}";
    
    }

    /// <summary>
    /// Request header names.
    /// </summary>
    internal static class RequestHeaders
    {
        /// <summary>
        /// DataServiceVersion request header
        /// </summary>
        internal const string DataServiceVersion = "DataServiceVersion";

        /// <summary>
        /// MaxDataServiceVersion request header
        /// </summary>
        internal const string MaxDataServiceVersion = "MaxDataServiceVersion";

        /// <summary>
        /// x-ms-version request header
        /// </summary>
        internal const string XMsVersion = "x-ms-version";

        /// <summary>
        /// Authorization request header
        /// </summary>
        internal const string Authorization = "Authorization";
    }

    /// <summary>
    /// HTTP Verbs
    /// </summary>
    internal static class HttpVerbs
    {
        /// <summary>
        /// POST HTTP verb
        /// </summary>
        internal const string Post = "POST";

        /// <summary>
        /// GET HTTP verb
        /// </summary>
        internal const string Get = "GET";

        /// <summary>
        /// MERGE HTTP verb
        /// </summary>
        internal const string Merge = "MERGE";

        /// <summary>
        /// DELETE HTTP verb
        /// </summary>
        internal const string Delete = "DELETE";
    }

    internal static class RequestContentType
    {
        internal const string Json = "application/json;odata=verbose";

        internal const string Atom = "application/atom+xml";
    }
}

MediaServiceContext.cs

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;
using Newtonsoft.Json.Linq;

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;

        private string _wamsEndpoint = "https://media.windows.net/";

        /// <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>
        /// Gets the endpoint for making REST API calls.
        /// </summary>
        public string WamsEndpoint
        {
            get
            {
                return _wamsEndpoint;
            }
        }

        /// <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 = HttpVerbs.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));
                }
            }
        }

        /// <summary>
        /// This function checks if we need to redirect all WAMS requests.
        /// </summary>
        public void CheckForRedirection()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(WamsEndpoint);
            request.AllowAutoRedirect = false;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, AccessToken));
            request.Method = HttpVerbs.Get;

            using (var response = (HttpWebResponse)request.GetResponse())
            {
                if (response.StatusCode == HttpStatusCode.Moved || response.StatusCode == HttpStatusCode.MovedPermanently)
                {
                    string newLocation = response.Headers["Location"];
                    if (!newLocation.Equals(_wamsEndpoint))
                    {
                        _wamsEndpoint = newLocation;
                        _accessToken = string.Empty;//So that we can force to get a new access token.
                        _accessTokenExpiry = DateTime.MinValue;
                    }
                }
            }
        }

        public Asset GetAssetReference(string assetId)
        {
            return new Asset(this, assetId);
        }

        public Asset GetAssetReference()
        {
            return new Asset(this);
        }

        /// <summary>
        /// List all assets in a media service.
        /// </summary>
        /// <returns>
        /// </returns>
        public IEnumerable<Asset> ListAssets()
        {
            List<Asset> assets = new List<Asset>();
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets", WamsEndpoint));
            request.Accept = RequestContentType.Json;
            request.Method = HttpVerbs.Get;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                using (StreamReader streamReader = new StreamReader(response.GetResponseStream(), true))
                {
                    var returnBody = streamReader.ReadToEnd();
                    JObject responseJsonObject = JObject.Parse(returnBody);
                    var items = responseJsonObject["d"]["results"];
                    foreach (var d in items)
                    {
                        var Id = d.Value<string>("Id");
                        var State = (AssetState)d.Value<int>("State");
                        var Options = (AssetEncryptionOption)d.Value<int>("Options");
                        var AlternateId = d.Value<string>("AlternateId");
                        var Created = d.Value<DateTime>("Created");
                        var LastModified = d.Value<DateTime>("LastModified");
                        var Name = d.Value<string>("Name");
                        assets.Add(new Asset(this, Id)
                        {
                            Name = Name,
                            State = State,
                            Options = Options,
                            AlternateId = AlternateId,
                            Created = Created,
                            LastModified = LastModified,
                        });
                    }
                }
            }
            return assets;
        }
    }
}

Asset.cs

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

namespace WAMSRestWrapper
{
    /// <summary>
    /// Class representing an asset in a media service
    /// </summary>
    public class Asset
    {
        private readonly MediaServiceContext _context;

        /// <summary>
        /// Creates an instance of <see cref="Asset"/>
        /// </summary>
        /// <param name="context">
        /// <see cref="MediaServiceContext"/>
        /// </param>
        internal Asset(MediaServiceContext context)
        {
            _context = context;
        }

        /// <summary>
        /// Creates an instance of <see cref="Asset"/>
        /// </summary>
        /// <param name="context">
        /// <see cref="MediaServiceContext"/>
        /// </param>
        /// <param name="id">
        /// Asset id
        /// </param>
        internal Asset(MediaServiceContext context, string id)
            : this(context)
        {
            Id = id;
        }

        /// <summary>
        /// Asset id.
        /// </summary>
        public string Id
        {
            get;
            internal set;
        }

        /// <summary>
        /// Asset state - Initialized (0), Deleted (1) [In Version 2.0, "Published" state is deprecated]   
        /// </summary>
        public AssetState State
        {
            get;
            set;
        }

        /// <summary>
        /// Date/time asset is created.
        /// </summary>
        public DateTime Created
        {
            get;
            internal set;
        }

        /// <summary>
        /// Date/time asset was last modified.
        /// </summary>
        public DateTime LastModified
        {
            get;
            internal set;
        }

        /// <summary>
        /// Alternate id for asset.
        /// </summary>
        public string AlternateId
        {
            get;
            set;
        }

        /// <summary>
        /// Friendly name for asset.
        /// </summary>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Encryption options for asset - None (0), StorageEncrypted (1), CommonEncryptionProtected (2)
        /// </summary>
        public AssetEncryptionOption Options
        {
            get;
            set;
        }

        /// <summary>
        /// Creates an asset
        /// </summary>
        public void Create()
        {
            if (string.IsNullOrWhiteSpace(Name))
            {
                Name = Guid.NewGuid().ToString();
            }

            string assetCreateRequestPayloadFormat = @"{0} ""Name"": ""{1}"", ""State"": ""{2}"", ""Options"":""{3}"", ""Created"":""{4}"", ""LastModified"":""{5}"" {6}";
            string requestBody = string.Format(CultureInfo.InvariantCulture, assetCreateRequestPayloadFormat, "{", Name, (int)State, (int)Options,
                Created.ToString("yyyy-MM-ddTHH:mm:ss"), LastModified.ToString("yyyy-MM-ddTHH:mm:ss"), "}");
            
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets/", _context.WamsEndpoint));
            request.Method = HttpVerbs.Post;
            request.ContentType = RequestContentType.Json;
            request.Accept = RequestContentType.Json;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, _context.AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            request.ContentLength = Encoding.UTF8.GetByteCount(requestBody);

            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();
                    JObject responseJsonObject = JObject.Parse(returnBody);
                    var d = responseJsonObject["d"];
                    Id = d.Value<string>("Id");
                    State = (AssetState)d.Value<int>("State");
                    Options = (AssetEncryptionOption)d.Value<int>("Options");
                    AlternateId = d.Value<string>("AlternateId");
                    Created = d.Value<DateTime>("Created");
                    LastModified = d.Value<DateTime>("LastModified");
                }
            }

        }

        /// <summary>
        /// Deletes the asset.
        /// </summary>
        public void Delete()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets('{1}')", _context.WamsEndpoint, Id));
            request.Method = HttpVerbs.Delete;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, _context.AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            var response = (HttpWebResponse)request.GetResponse();
        }

        /// <summary>
        /// Updates an asset
        /// </summary>
        public void Update()
        {
            string assetCreateRequestPayloadFormat = @"{0} ""Name"": ""{1}"", ""AlternateId"": ""{2}"" {3}";
            string requestBody = string.Format(CultureInfo.InvariantCulture, assetCreateRequestPayloadFormat, "{", Name, AlternateId, "}");

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets('{1}')", _context.WamsEndpoint, Id));
            request.Method = HttpVerbs.Merge;
            request.ContentType = RequestContentType.Json;
            request.Accept = RequestContentType.Json;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, _context.AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            request.ContentLength = Encoding.UTF8.GetByteCount(requestBody);

            using (StreamWriter streamWriter = new StreamWriter(request.GetRequestStream()))
            {
                streamWriter.Write(requestBody);
            }
            var response = (HttpWebResponse)request.GetResponse();
        }

        /// <summary>
        /// Publishes an asset. This function is deprecated in version 2.0.
        /// </summary>
        public void Publish()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets('{1}')/Publish", _context.WamsEndpoint, Id));
            request.Method = HttpVerbs.Post;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, _context.AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            request.ContentLength = 0;
            var response = (HttpWebResponse)request.GetResponse();
        }

        /// <summary>
        /// Gets information about an asset.
        /// </summary>
        public void Get()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(string.Format(CultureInfo.InvariantCulture, "{0}Assets('{1}')", _context.WamsEndpoint, Id));
            request.Method = HttpVerbs.Get;
            request.Accept = RequestContentType.Json;
            request.Headers.Add(RequestHeaders.XMsVersion, RequestHeaderValues.XMsVersion);
            request.Headers.Add(RequestHeaders.Authorization, string.Format(CultureInfo.InvariantCulture, RequestHeaderValues.Authorization, _context.AccessToken));
            request.Headers.Add(RequestHeaders.DataServiceVersion, RequestHeaderValues.DataServiceVersion);
            request.Headers.Add(RequestHeaders.MaxDataServiceVersion, RequestHeaderValues.MaxDataServiceVersion);
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                using (StreamReader streamReader = new StreamReader(response.GetResponseStream(), true))
                {
                    var returnBody = streamReader.ReadToEnd();
                    JObject responseJsonObject = JObject.Parse(returnBody);
                    var d = responseJsonObject["d"];
                    Id = d.Value<string>("Id");
                    State = (AssetState)d.Value<int>("State");
                    Options = (AssetEncryptionOption)d.Value<int>("Options");
                    AlternateId = d.Value<string>("AlternateId");
                    Created = d.Value<DateTime>("Created");
                    LastModified = d.Value<DateTime>("LastModified");
                }
            }
        }
    }

    /// <summary>
    /// Enumeration indicating asset state.
    /// Please note that version 2.0, Publish Asset action is deprecated. Hence it is removed from here.
    /// </summary>
    public enum AssetState
    {
        Initialized = 0,
        //Published = 1,
        Deleted = 1,
    }

    /// <summary>
    /// Enumeration for asset encryption options.
    /// </summary>
    public enum AssetEncryptionOption
    {
        None = 0,
        StorageEncrypted = 1,
        CommonEncryptionProtected = 2,
    }

}

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]