Using the REST API Service (Messenger Connect)

Ff748607.note(en-us,MSDN.10).gifNote:
Current information about Live Connect is now available in the Windows Live Developer Center. The information in the following sections is provided for legacy purposes only.

This topic provides samples that use the Representational State Transfer (REST) API of Windows Live Messenger Connect to communicate with Windows Live. These samples demonstrate how to:

  • Send HTTP requests.
  • Create, update, retrieve and delete resources in Windows Live.
  • Construct payloads and process response.

To learn more about Windows Live resources, see the following topics:

Accessing Windows Live resources by means of the REST API requires a valid access token and a resource ID in the form of a Universal Resource Identifier (URI). One method of acquiring an access token is to use the technique that is described in the topic Acquiring an Access Token. You construct the URI for the resource that you wish to access by starting at the Windows Live root service endpoint and progressively requesting more detailed information until you access the specific resource of interest.

The following code example shows how to construct a basic HTTP GET Request.

private HttpWebRequest CreateHttpRequest(string serviceEndPoint, 
    string oAuthToken)
{
    HttpWebRequest request = 
        (HttpWebRequest)WebRequest.Create(serviceEndPoint);
    request.Method = "GET";
    request.Accept = "application/atom+xml";
    request.Headers.Add(HttpRequestHeader.Authorization, oAuthToken);
    return request;
}

An example of a root service endpoint value is "http://apis.live.net/V4.1/". After sending the request, you must process the response. The Accept property of the request determines the format of the response data. If the GET request specifies the “application/atom+xml” format, you can process the response as an XML document. The following example shows how to send the request and format the response into an XML document that can be parsed for information.

private XmlDocument GetRootLevelServiceDocument(
    string serviceEndPoint, string oAuthToken)
{
    XmlDocument xmlDoc = new XmlDocument();
    HttpWebRequest request = CreateHttpRequest(serviceEndPoint, 
        oAuthToken);
 
    using (HttpWebResponse response = 
        (HttpWebResponse)request.GetResponse())
    {
        using (XmlReader reader = 
            XmlReader.Create(response.GetResponseStream(), 
            new XmlReaderSettings() { CloseInput = true }))
        {
            xmlDoc.Load(reader);

            string data = ReadResponse(response);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                LogMsg(string.Format("Error: {0}", data));
                LogMsg(string.Format(
                    "Unexpected status code returned: {0}", 
                    response.StatusCode));
            }
        }
    }

    return xmlDoc;
}

To access one of the top-level collections for a Windows Live user, you must send an HTTP GET request to the root service endpoint with a valid access token. You parse the response to determine the address for the top-level collection that you want to access. You must issue another HTTP GET request for this address in order to obtain the collection contents.

The following code example shows how to determine the URI address for the contacts collection.

// Acquire the contacts collection endpoint URI.
private string FindContactsCollectionEndPoint(
    string serviceEndPoint, string oAuthToken)
{
    string contactsCollectionEndPoint = null;
    XmlDocument rootLevelServiceDoc = 
        GetRootLevelServiceDocument(serviceEndPoint, oAuthToken);
    XmlDocument serviceDocument = 
        GetServiceDocument(rootLevelServiceDoc, "Contacts", oAuthToken);
    contactsCollectionEndPoint = 
        ConstructUri(serviceDocument, "AllContacts");
    if (string.IsNullOrEmpty(contactsCollectionEndPoint))
    {
        throw new ArgumentException(
            "unable to find contacts collection URI");
    }
    return contactsCollectionEndPoint;
}

private XmlDocument GetRootLevelServiceDocument(
    string serviceEndPoint, string oAuthToken)
{
    XmlDocument xmlDoc = new XmlDocument();
    HttpWebRequest request = CreateHttpRequest(serviceEndPoint, 
        oAuthToken);
 
    using (HttpWebResponse response = 
        (HttpWebResponse)request.GetResponse())
    {
        using (XmlReader reader = 
            XmlReader.Create(response.GetResponseStream(), 
            new XmlReaderSettings() { CloseInput = true }))
        {
            xmlDoc.Load(reader);

            string data = ReadResponse(response);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                LogMsg(string.Format("Error: {0}", data));
                LogMsg(string.Format(
                    "Unexpected status code returned: {0}", 
                    response.StatusCode));
            }
        }
    }

    return xmlDoc;
}

private XmlDocument GetServiceDocument(XmlDocument serviceDocument, 
    string collectionName, string oAuthToken)
{
    String resourceURI;
    resourceURI = ConstructUri(serviceDocument, collectionName);

    XmlDocument resourceXML = new XmlDocument();

    // GET the resource. 
    HttpWebRequest request = CreateHttpRequest(resourceURI, oAuthToken);

    try
    {
        using (HttpWebResponse response = 
            (HttpWebResponse)request.GetResponse())
        {
            resourceXML.Load(response.GetResponseStream());
        }
    }
    catch (WebException ex)
    {
        using (HttpWebResponse response = ex.Response as HttpWebResponse)
        {
            if (response != null)
            {
                string errorMsg = ReadResponse(response);
                LogMsg(string.Format("Error:{0}", errorMsg));
                LogMsg(string.Format("Unexpected status code returned: {0} ", 
                    response.StatusCode));
            }
        }
    }

    return resourceXML;
}

private string ConstructUri(XmlDocument serviceDocument,
    string collectionName)
{
    string resourceURI;

    XmlNameTable m_nameTable;
    XmlNamespaceManager m_nsmgr;

    m_nameTable = new NameTable();
    m_nsmgr = new XmlNamespaceManager(m_nameTable);
    m_nsmgr.AddNamespace("x", "http://www.w3.org/2007/app");
    m_nsmgr.AddNamespace("atom", "http://www.w3.org/2005/Atom");


    // Get xml:base attribute value from <workspace> node.
    String BaseUri = serviceDocument.DocumentElement.SelectSingleNode(
        "//x:workspace/@xml:base", m_nsmgr).Value;

    // Retrieve href attribute value from the Contacts collection.
    string xPathExpression = String.Format(
        "//x:collection[atom:title='{0}']/@href", collectionName);
    resourceURI =
        serviceDocument.DocumentElement.SelectSingleNode(xPathExpression,
        m_nsmgr).Value;

    // Check if resource URI is absolute.
    if (!resourceURI.StartsWith("http://") &&
        !resourceURI.StartsWith("https://"))
    {
        // Combine the two to form the resource URI.
        resourceURI = BaseUri + resourceURI;
    }

    return resourceURI;
}

An HTTP GET request with the URI for the contacts collection returns the list of contacts for the user in the response data. The following code example shows how to parse the collection data. This example uses the LogMsg user function to display the contact name and its ID value to the web page.

private void DisplayAllContacts(string oAuthToken)
{
    try
    {
        // Get the list of contacts.
        string contactsCollectionEndPoint = 
            FindContactsCollectionEndPoint(serviceEndPoint, oAuthToken);
        XmlDocument allContacts = 
            GetAllContacts(contactsCollectionEndPoint, oAuthToken);

        // Initialize the namespace manager for the XPath search 
        // expression.
        XmlNamespaceManager nsmgr = 
            new XmlNamespaceManager(allContacts.NameTable);
        nsmgr.AddNamespace("atom", "http://www.w3.org/2005/Atom");
        nsmgr.AddNamespace("p3", 
            "http://schemas.microsoft.com/ado/2007/08/dataservices");
        nsmgr.AddNamespace("p4", 
        "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");

        // Iterate across the list.
        XmlNodeList xmlList = allContacts.GetElementsByTagName("entry");

        for (int i = 0; i < xmlList.Count; i++)
        {
            string contactName, contactID;

            contactID = xmlList[i].SelectSingleNode(
                "descendant::atom:id", nsmgr).InnerXml;
            contactName = xmlList[i].SelectSingleNode(
                "descendant::p3:FormattedName", nsmgr).InnerXml;

            // Display the contact information.
            LogMsg(string.Format("Contact: {0}, &nbsp;&nbsp;&nbsp;ID: {1}", 
                contactName, contactID));
        }
    }
    catch (WebException ex)
    {
        using (HttpWebResponse response = ex.Response as HttpWebResponse)
        {
            if (response != null)
            {
                string errorMsg = ReadResponse(response);
                LogMsg(string.Format("Error:{0}", errorMsg));
                LogMsg(string.Format(
                    "Unexpected status code returned: {0} ", 
                    response.StatusCode));
            }
        }
    }
}

private XmlDocument GetAllContacts(string contactsCollectionUri, 
    string oAuthToken)
{
    XmlDocument xmlDoc = new XmlDocument();
    //string data = null;

    try
    {
        HttpWebRequest request = 
            CreateHttpRequest(contactsCollectionUri, oAuthToken);

        using (HttpWebResponse response = 
            (HttpWebResponse)request.GetResponse())
        {
            if (response.StatusCode == HttpStatusCode.OK)
            {
                using (XmlReader reader = XmlReader.Create(
                    response.GetResponseStream(), new XmlReaderSettings() 
                    { CloseInput = true }))
                {
                    xmlDoc.Load(reader);
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        LogMsg(string.Format(
                            "Unexpected status code returned: {0}", 
                            response.StatusCode));
                    }
                }
            }
        }
    }
    catch (WebException ex)
    {
        using (HttpWebResponse response = ex.Response as HttpWebResponse)
        {
            if (response != null)
            {
                string errorMsg = ReadResponse(response);
                LogMsg(string.Format("Error:{0}", errorMsg));
                LogMsg(string.Format("Unexpected status code returned: {0}", 
                    response.StatusCode));
            }
        }
    }

    return xmlDoc;
}

You obtain information for a specific collection entry either by processing the response for the collection or by issuing an HTTP GET request for the individual entry’s URI address. The following code example shows how to request the information for a specific contact.

private void DisplayContactInfo(string contactUri, string oAuthToken)
{
    XmlDocument contactDoc = GetResource(contactUri, oAuthToken);

    // Initialize the namespace manager for the XPath search 
    // expression.
    XmlNodeList xmlList;
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(
        contactDoc.NameTable);

    nsmgr.AddNamespace("xml", "http://www.w3.org/XML/1998/namespace");
    nsmgr.AddNamespace("atom", "http://www.w3.org/2005/Atom");
    nsmgr.AddNamespace("p2", 
        "http://schemas.microsoft.com/ado/2007/08/dataservices");

    // Display the contact information.
    string contactName;

    contactName = contactDoc.SelectSingleNode(
        "descendant::p2:FormattedName", nsmgr).InnerXml;
    LogMsg(string.Format("Contact Information for {0}", contactName));

    LogMsg("&nbsp;&nbsp;Emails:");
    xmlList = contactDoc.SelectNodes(
        "descendant::p2:Emails/p2:element/p2:Address", nsmgr);
    for (int i = 0; i < xmlList.Count; i++)
    {
        LogMsg(string.Format("&nbsp;&nbsp;&nbsp;&nbsp;{0}", 
            xmlList[i].InnerXml));
    }

    LogMsg("&nbsp;&nbsp;Locations:");
    xmlList = contactDoc.SelectNodes(
        "descendant::p2:Locations/p2:element/p2:Formatted", nsmgr);
    for (int i = 0; i < xmlList.Count; i++)
    {
        LogMsg(string.Format("&nbsp;&nbsp;&nbsp;&nbsp;{0}", 
            xmlList[i].InnerXml));
    }

    LogMsg("&nbsp;&nbsp;Phone Numbers:");
    xmlList = contactDoc.SelectNodes(
        "descendant::p2:PhoneNumbers/p2:element/p2:Number", nsmgr);
    for (int i = 0; i < xmlList.Count; i++)
    {
        LogMsg(string.Format("&nbsp;&nbsp;&nbsp;&nbsp;{0}", 
            xmlList[i].InnerXml));
    }

    LogMsg("&nbsp;&nbsp;URLs:");
    xmlList = contactDoc.SelectNodes(
        "descendant::p2:Urls/p2:element/p2:Value", nsmgr);
    for (int i = 0; i < xmlList.Count; i++)
    {
        LogMsg(string.Format("&nbsp;&nbsp;&nbsp;&nbsp;{0}", 
            xmlList[i].InnerXml));
    }
}

You delete a resource from Windows Live by sending an HTTP DELETE request to the resource’s URI address. If the removal is successful, the status code of the response is NoContent. The following code example shows how to delete a contact resource.

// Create a request.
HttpWebRequest request = 
    (HttpWebRequest)WebRequest.Create(entityUri);
request.Method = "DELETE";
request.Accept = "application/atom+xml";
request.Headers.Add(
    HttpRequestHeader.Authorization, oAuthToken);

// Get and process response.
using (HttpWebResponse response = 
    (HttpWebResponse)request.GetResponse())
{
    if (response.StatusCode == HttpStatusCode.NoContent)
    {
        // Delete succeeded. Refresh the contact list. 
        // cmbContacts is an ASP .NET DropDownList control 
        // that contains the list of current contacts.
        PopulateContacts(cmbContacts, oAuthToken);
    }
    else
    {
        data = ReadResponse(response);
        LogMsg(string.Format("Error: {0}", data));
        LogMsg(string.Format(
            "Unexpected status code returned: {0}", 
            response.StatusCode));
    }
}

You use an HTTP POST request to create a new Windows Live resource. You send a POST request to the collection URI that will contain the new resource. The POST request must contain a payload that describes the resource that you are creating.

You use an HTTP PUT request to modify an existing resource. When you modify an existing resource, you send an HTTP PUT request to the URI for the resource that you are updating. The PUT request must contain a payload that describes the resource that you are updating.

The following code example shows how to update the property values for an existing contact.

private void SendUpdatesBack(XmlDocument contactPayloadForUpdate, 
    string contactUri, string oAuthToken)
{
    // XML payload for PUT (update) request.
    string requestPayload = contactPayloadForUpdate.OuterXml;

    try
    {
        // Update the contact.
        HttpWebRequest request = 
            (HttpWebRequest)WebRequest.Create(contactUri);
        request.Method = "PUT";
        request.Headers.Add(HttpRequestHeader.Authorization, 
            oAuthToken);
        
        // Write the payload to the request.
        UTF8Encoding encoding = new UTF8Encoding();
        request.ContentLength = encoding.GetByteCount(requestPayload);
        request.ContentType = acceptType;

        // Write request data over the wire.
        using (Stream reqStream = request.GetRequestStream())
        {
            reqStream.Write(encoding.GetBytes(requestPayload), 0, 
                encoding.GetByteCount(requestPayload));
        }

        // Get the response and read it into a string.
        using (HttpWebResponse response = 
            (HttpWebResponse)request.GetResponse())
        {
            string data = ReadResponse(response);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                LogMsg(string.Format("Error: {0}", data));
                LogMsg(string.Format("Unexpected status code returned: {0}", 
                    response.StatusCode));
            }
            else
            {
                LogMsg(string.Format("Contact updated... Contact URI={0}", 
                    contactUri));
            }
        }
    }
    catch (WebException ex)
    {
        using (HttpWebResponse response = ex.Response as HttpWebResponse)
        {
            if (response != null)
            {
                string errorMsg = ReadResponse(response);
                LogMsg(string.Format("Error:{0}", errorMsg));
                LogMsg(string.Format("Unexpected status code returned: {0}", 
                    response.StatusCode));
            }
        }
    }
}

An HTTP payload can follow a variety of standard formats: Atom, RSS, JavaScript Object Notation (JSON) and others. The value that you assign to the Accept property for the POST or PUT request identifies the particular format that the request uses. The code examples in this section use the Atom format.

An Atom payload can be constructed either by adding XML nodes in the proper order or by using a string template that constructs the XML formatted data in its entirety. The following code example uses a string template to construct a payload that adds a new contact to the contacts collection. After you send the POST request, check the response status code to verify that the resource object was created successfully.

private string AddContact(string contactCollectionEndPoint, 
    string firstName, string lastName, string oAuthToken)
{
    const string ContactTemplate = 
        @"<entry xmlns='http://www.w3.org/2005/Atom' 
          xmlns:p2='http://schemas.microsoft.com/ado/2007/08/dataservices'>
            <content type='application/xml'>
              <properties xmlns='http://www.w3.org/2001/XMLSchema-instance'>
                <p2:FirstName>{0}</p2:FirstName>
                <p2:LastName>{1}</p2:LastName>
              </properties>
            </content>
          </entry>";
    string requestPayload = string.Format(ContactTemplate, firstName, 
        lastName);

    string data = null;

    if (string.IsNullOrEmpty(contactCollectionEndPoint))
    {
        throw new ArgumentOutOfRangeException("entityUri");
    }

    try
    {
        // Construct the POST request.
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
            contactCollectionEndPoint);
        request.Method = HttpPostMethod;
        request.Headers.Add(HttpRequestHeader.Authorization, 
            oAuthToken);
 
        // Write the payload to the request.
        UTF8Encoding encoding = new UTF8Encoding();
        request.ContentLength = encoding.GetByteCount(
            requestPayload);
        request.ContentType = acceptType;

        // Write request data over the wire.
        using (Stream reqStream = request.GetRequestStream())
        {
            reqStream.Write(encoding.GetBytes(requestPayload), 
                0, encoding.GetByteCount(requestPayload));
        }

        // Get the response and read it into a string.
        using (HttpWebResponse response = 
            (HttpWebResponse)request.GetResponse())
        {
            data = ReadResponse(response);
            if (response.StatusCode != HttpStatusCode.Created)
            {
                LogMsg(string.Format("Error: {0}", data));
                LogMsg(string.Format(
                    "Unexpected status code returned: {0}", 
                    response.StatusCode));
            }
            else
            {
                LogMsg(string.Format(
                    "Contact created... Contact URI={0}", 
                    response.Headers[HttpResponseHeader.Location]));
            }
        }
    }
    catch (WebException ex)
    {
        using (HttpWebResponse response = ex.Response as 
            HttpWebResponse)
        {
            if (response != null)
            {
                string errorMsg = ReadResponse(response);
                LogMsg(string.Format("Error:{0}", errorMsg));
                LogMsg(string.Format(
                    "Unexpected status code returned: {0}", 
                    response.StatusCode));
            }
        }
    }

    return data;
}

When you update an existing resource, the payload updates all data for the resource. If you wish to maintain the same value for some of the resource properties, you must get the existing resource’s data, modify those properties that are changing, and write everything back to the Windows Live server.

The following code example gets the data for an existing contact resource, changes the LastName value, and writes the resource back to the Windows Live server. In this example, the resource URI address is the value of contactUri, and updLastName is the new value for the LastName property.

private void UpdateContactInfo(string updLastName, string contactUri, 
    string oAuthToken)
{
    XmlDocument contactDoc = GetResource(contactUri, oAuthToken);
    XmlNode oldLastName;
    XmlElement root = contactDoc.DocumentElement;

    // Initialize the namespace manager for the XPath search 
    // expression.
    XmlNamespaceManager nsmgr = new XmlNamespaceManager(
        contactDoc.NameTable);

    nsmgr.AddNamespace("xml", "http://www.w3.org/XML/1998/namespace");
    nsmgr.AddNamespace("atom", "http://www.w3.org/2005/Atom");
    nsmgr.AddNamespace("p2",
        "http://schemas.microsoft.com/ado/2007/08/dataservices");
    nsmgr.AddNamespace("y",
        "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");

    // Select properties node. This is where we will replace 
    // <LastName> node with a new node.
    XmlNode properties = 
        root.SelectSingleNode("//atom:content/y:properties", nsmgr);
    oldLastName = 
        root.SelectSingleNode("//atom:content/y:properties/p2:LastName", 
        nsmgr);

    XmlNode newLastName = contactDoc.CreateElement("p2:LastName", 
        "http://schemas.microsoft.com/ado/2007/08/dataservices");
    newLastName.InnerText = updLastName;
    properties.ReplaceChild(newLastName, oldLastName);

    // Send updates back. We need to construct payload 
    // (<entry> <content>...</content></entry>) from the contactDoc.
    XmlDocument contactPayloadForUpdate = new XmlDocument();
    XmlNamespaceManager nsmgr2 = 
        new XmlNamespaceManager(contactPayloadForUpdate.NameTable);
    nsmgr2.AddNamespace("p2", 
        "http://schemas.microsoft.com/ado/2007/08/dataservices");
    nsmgr2.AddNamespace("atom", "http://www.w3.org/2005/Atom");

    XmlElement entry = contactPayloadForUpdate.CreateElement("entry", 
        "http://www.w3.org/2005/Atom");
    contactPayloadForUpdate.AppendChild(entry);

    // get updated content node from source
    XmlNode copiedContent = 
        contactPayloadForUpdate.ImportNode(root.SelectSingleNode(
        "atom:content", nsmgr), true);
    entry.AppendChild(copiedContent);

    SendUpdatesBack(contactPayloadForUpdate, contactUri, oAuthToken);
}

Show: