Managing ContentTypes with the MashPoint REST API

Now it is time to create, update and delete ContentTypes. I suggest that you read all previous posts before continuing on.

We will create our new ContentType in the web we created earlier. The URI to the ContentTypes collection on my server looks like this; http://jndtvbx64/mashpoint/1/subweb/ContentTypes. If I browse to that URI I see that I don't have any ContentTypes yet. We create a new ContentType by sending a POST request to the ContentTypes URI.

This sample will be a bit more complete than the others. We will not hard code the URIs but read them from the XHTML returned. This is one of the fundamentals of a RESTFul API. The resource representations are hypermedia that the client understand. The client SHOULD not assume anything about the resources URIs but rather read them from the hypermedia. This way a client won't break if the server decides to change the URI namespace.

As I said we create a new ContentType by sending a POST request to the URI of the ContentTypes collection. We pass the Name, Description,Group and ParentContentType. You MUST send Name and ParentContentType.

After this we read the URI to the field links collection so we can associate site columns with our new content type. I'm adding the site column we created in the previous post called "A new field" and also the "ManagersName" column. Finally we POST this to the field links URI.
public void CreateContentType()
{
    string uri = L("http://server/mashpoint/1/subweb/ContentTypes");

    WebClient wc = new WebClient();
    wc.Credentials = CredentialCache.DefaultCredentials;

    NameValueCollection v = new NameValueCollection();

    v["Description"] = "A new Design Document";
    v["Group"] = "MashPoint";
    v["Name"] = "DesignDocument";
    v["ParentContentType"] = "Document";

    XmlDocument dom = LoadDom(wc.UploadValues(uri, "POST", v));
    string newuri = wc.ResponseHeaders.Get("Location");
    Console.WriteLine(newuri);

    // get the URI to the FieldLink collection of the ContentType
    string fieldLinksUri = 
        FindURI(dom, "Microsoft:SharePoint:SPFieldLinkCollection");
                
    v = new NameValueCollection();
    v.Add("FieldName", "A new field");
    v.Add("FieldName", "ManagersName");

    WebClientHelper.UploadValues(fieldLinksUri, "POST", wc, v);
    newuri = wc.ResponseHeaders.Get("Location");
    Console.WriteLine(newuri);
}
Here is the created ContentType.
created
Let's take a closer look at the code above. As you can see we are using two new functions; LoadDom and FindURI. We load the response into an XmlDocument so we can parse out the correct URI to the other resources we have to update.
XmlDocument LoadDom(byte[] b)
{
    using (MemoryStream ms = new MemoryStream(b))
    {
        XmlDocument dom = GetAuthenticatedXmlDocument();
        dom.Load(ms);
        return dom;
    }
}
XmlDocument GetAuthenticatedXmlDocument()
{
    XmlDocument dom = new XmlDocument();
    XmlUrlResolver resolver = new XmlUrlResolver();
    resolver.Credentials = CredentialCache.DefaultCredentials;
    dom.XmlResolver = resolver;
    return dom;
}
The FindURI function.
public string FindURI(XmlDocument dom, string rel)
{
    string pattern = string.Format("//a[@rel='{0}']", rel);
    XmlNodeList nodes = dom.SelectNodes(pattern);
    if (nodes.Count == 0)
    {
        string msg = string.Format("No link to [{0}] found", rel);
        throw new ArgumentException(msg);
    }
    return nodes[0].Attributes["href"].Value;
}
Let's take a closer look at the XHTML representation of an object. An object is enclosed in a div with it's class attribute set to the .NET Type of the object. Then all the properties follows. A property is enclosed in a div with it's class set to property. A property has a name and a value. The value div has a class of value + the .NET type of the value. If the property is a primitive type the value is the contents of the div. If it is a complex object or a collection an anchor is written with it's href pointing to the resource and it's rel attribute set to the type of the object referenced.
<div class="Microsoft:SharePoint:SPContentType">
  <div class="property">
    <div class="name">Description</div>
    <div class="value System:String">A new Design Document</div>
  </div>
  <div class="property">
    <div class="name">DisplayFormTemplateName</div>
    <div class="value System:String">DocumentLibraryForm</div>
  </div>

  <div class="property">
    <div class="name">EventReceivers</div>
    <a class="value" 
        href="http://jndtvbx64/mashpoint/1/subweb/ContentTypes/DesignDocument/EventReceivers" 
        rel="Microsoft:SharePoint:SPEventReceiverDefinitionCollection">EventReceivers</a>
  </div>
  <div class="property">
    <div class="name">FieldLinks</div>
    <a class="value" 
        href="http://jndtvbx64/mashpoint/1/subweb/ContentTypes/DesignDocument/FieldLinks" 
        rel="Microsoft:SharePoint:SPFieldLinkCollection">FieldLinks</a>
  </div>
 
</div>
As you can see this is meant to be parsed by clients but with the added benefit of being rendered and used in a web browser. So it is very easy to discover the object model by just using your web browser.
Lets revisit the sample where we created a new ContentType. As you saw we had to do two POSTS to create a minimal ContentType. There is actually an easier way to create a ContentType. We can send the FieldLinks in the initial POST.
public void CreateContentTypeWithOnePOST()
{
    string uri = L("http://server/mashpoint/1/subweb/ContentTypes");

    WebClient wc = new WebClient();
    wc.Credentials = CredentialCache.DefaultCredentials;

    NameValueCollection v = new NameValueCollection();

    v["Description"] = "A new Design Document";
    v["Group"] = "MashPoint";
    v["Name"] = "DesignDocument2";
    v["ParentContentType"] = "Document";

    v.Add("FieldLink", "A new field");
    v.Add("FieldLink", "ManagersName");

    byte[] body = WebClientHelper.UploadValues(uri, "POST", wc, v);

    XmlDocument dom = LoadDom( body );
    string newuri = wc.ResponseHeaders.Get("Location");
    Console.WriteLine(newuri);
}
As you can see we are sending the FieldLinks in the initial request and because it is a multivalued field we need to use our helper class to send it.
As always to update the ContentType we send a PUT request to the URI of the ContentType.
public void UpdateContentType()
{
    string uri = L("http://server/mashpoint/1/subweb/ContentTypes/DesignDocument");

    WebClient wc = new WebClient();
    wc.Credentials = CredentialCache.DefaultCredentials;

    NameValueCollection v = new NameValueCollection();

    v["Description"] = "Updated desription";
    v["Hidden"] = true.ToString();

    XmlDocument dom = LoadDom(wc.UploadValues(uri, "PUT", v));
    Console.WriteLine( dom.OuterXml );
}
And finally to delete a ContentType send a DELETE request to the URI referencing the ContentType.
public void DeleteContentType()
{
    string uri = L("http://server/mashpoint/1/subweb/ContentTypes/DesignDocument");
    WebClient wc = new WebClient();
    wc.Credentials = CredentialCache.DefaultCredentials;
    wc.UploadString(uri, "DELETE", string.Empty);
}
In the next post we will manage EventReceivers using the REST API.
 

Posted Aug 19 2009, 11:00 AM by Jonas Nilsson
Filed under: ,

Blogs

    MashPoint - A Breakthrough in SharePoint Data Integration
  • Home

Bamboo Nation, Media Sponsor of:

SPTechCon

Download MashPoint Now!

MashPoint - Data Integration for SharePointDownload the official MashPoint release, available as of November 7th, 2008.

Jonas Nilsson Q&A

Bamboo Nation Almost Everywhere

Follow Bamboo Nation on:Bamboo Solutions on Facebook

Bamboo Solutions on Google+

Bamboo Solutions on LinkedIn

Bamboo Solutions on Twitter

Bamboo Solutions on YouTube

SharePoint Calendars

SharePoint Calendars

Bamboo Solutions Corporation, 2002-2012