Access historic revisions of SharePoint Publishing Pages using CSOM

Recently I received a questions from a customer who was looking for a way to access content of historic revisions of a publishing pages using SharePoint client side object model (CSOM).

Using server side object model this can be achieved using code similar to the following (here we access historic versions of the Title and the PublishingPageContent field):

SPSite site = new SPSite("http://contoso:3200");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["Pages"];

SPListItem item = list.Items[2];

Console.WriteLine("---------------------------");
Console.WriteLine(item["PublishingPageContent"]);

foreach (SPListItemVersion version in item.Versions)
{
    Console.WriteLine(version.VersionLabel);
    Console.WriteLine(version["Title"]);
    Console.WriteLine(version["PublishingPageContent"]);
}

The equivalent CSOM code would look like this:

// this code works only with SharePoint Online and SharePoint Server 2019
using (ClientContext ctx = new ClientContext("http://contoso:3200"))
{
    ctx.Load(ctx.Web);
    ctx.ExecuteQuery();

    // Retrieve list by title  
    List list = ctx.Web.Lists.GetByTitle("Pages");
    ctx.Load(list, L => L.Id);

    // Retrieve all items from above list
    ListItemCollection listItems = 
         list.GetItems(CamlQuery.CreateAllItemsQuery());
    ctx.Load(listItems, IC => IC.Include(I => I.Id, I => I.DisplayName));
    ctx.ExecuteQuery();

    // select the ListItem we are interested in
    ListItem item = listItems[2];
    Console.WriteLine(item.DisplayName);

    ctx.Load(item, li => li.Versions);
    ctx.ExecuteQuery();

    Console.WriteLine(item.Versions.Count);

    foreach (ListItemVersion version in item.Versions)
    {
        Console.WriteLine(version.VersionLabel);
        Console.WriteLine(version["Title"]);
        Console.WriteLine(version["PublishingPageContent"]);
    }
}

The problem with the CSOM code above is that the above listed CSOM API calls to retrieve historic versions of List Items is only available in SharePoint Online and SharePoint Server 2019. So this method cannot be used with previous versions of SharePoint.

After a little bit of research I identified the following method which utilizes the Lists.asmx web service which can be also be used with all OnPremise versions of SharePoint (this method cannot be used with SharePoint Online):

using (ClientContext ctx = new ClientContext("http://contoso:3200"))
{
    ctx.Load(ctx.Web);
    ctx.ExecuteQuery();

    // Retrieve list by title  
    List list = ctx.Web.Lists.GetByTitle("Pages");
    ctx.Load(list, L => L.Id);

    // Retrieve all items from above list
    ListItemCollection listItems = 
         list.GetItems(CamlQuery.CreateAllItemsQuery());
    ctx.Load(listItems, IC => IC.Include(I => I.Id, I => I.DisplayName));
    ctx.ExecuteQuery();

    // select the ListItem we are interested in
    ListItem item = listItems[2];
    Console.WriteLine(item.DisplayName);

    // Use Lists.asmx web service to retrieve historic version information
    ListService.Lists listService = new ListService.Lists();
    listService.Url = ctx.Url + "/_vti_bin/Lists.asmx";
    listService.Credentials = CredentialCache.DefaultCredentials;

    // Retrieve all versions for selected fields from list item using web service  
    XmlNode nodeUIVersions = 
      listService.GetVersionCollection(
        list.Id.ToString(), item.Id.ToString(), "_UIVersionString");
    XmlNode nodePageContent = 
      listService.GetVersionCollection(list.Id.ToString(),
        item.Id.ToString(), "PublishingPageContent");
    XmlNode nodeTitle =
      listService.GetVersionCollection(list.Id.ToString(),
        item.Id.ToString(), "Title");

    // the number of versions for each field should be the same so we can retrieve them 
    // using a single loop
    for (int i = 0; i < nodeUIVersions.ChildNodes.Count; i++)
    {
        Console.WriteLine("-------------------------------------");
        Console.WriteLine("Version: " + 
           nodeUIVersions.ChildNodes[i].Attributes["_UIVersionString"].Value);
        Console.WriteLine("List Item Title: " +
           nodeTitle.ChildNodes[i].Attributes["Title"].Value);
        Console.WriteLine("PublishingPageContent: " +
           nodePageContent.ChildNodes[i].Attributes["PublishingPageContent"].Value);
    }
}

To use the code above you need to create a C# Visual studio project and add a web reference to the _vti_bin/Lists.asmx web service (References / Add Service Reference… / Advanced… / Add Web Reference…).

In the following Dialog you need to name the WebReference “ListService”. Alternatively you can change all references to ListService in the code above to the name you selected in this dialog.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.