Revision History within MCMS

by Dan Matthews 25. March 2007 13:24

Microsoft Content Management Server provides a fairly powerful revision history tool within the Web Author. It shows a list of versions, and can compare them for differences. However, MCMS doesn’t really help too much when trying to present older revisions to subscribers outside of the Web Author.

 

Typically, this situation could occur when a user might want to see what a page looked like a week, month or even a year ago. Whilst this situation would be rare in an Internet scenario, in an Intranet (or Extranet) scenario it would be more common. If an end-user had to contact one of the MCMS authors every time they needed to check the historical details of a page then it would rapidly become a fairly tedious and time-consuming task using the Web Author.

 

Ideally, there would be an extra flag that we could pass on the page QueryString to obtain a page version from a specific point in time. We could then show a list of revisions as hyperlinks and the end-user could click through to the version they wanted. Unfortunately, MCMS doesn’t provide that. Out-the-box, the pages you can ask for using URLs will give you either the published or (if present) unpublished version, and that’s the lot.

 

Thankfully, using the MCMS API and a little bit of trickery, there is a fairly simple way to get an older revision.

 

To get an old version of a current posting, the technique is to create a new posting based on the same template, and then copy across placeholder data as required. (I’ve tested this with HTML placeholders and it works fine. It may well work with image or attachment placeholders as well, although some tweaking may be required in the code.) The new posting can then be referenced by its ‘inner’ URL and you’re in business.

 

Here’s a step-by-step how to do it:

 

1)      Create a new .aspx in the root of the website called “RevisionHistory.aspx. (Note: if preferred, you can create it as a MCMS template and create a posting from it. That works perfectly well. You’ll just need to change the page reference in the code fragments below.)

2)      Create a new channel from your channel root called “_Historical”. Ensure that the properties of this channel are set to not crawlable and not indexable otherwise you might get some interesting search/navigation conundrums. Write access to this channel should be granted to everyone.

3)      In the Page_Load of RevisionHistory.aspx, put the following code (you’ll need to add a using directive for Microsoft.ContentManagement.Publishing, if it’s not on the page already):

 

if(Request.QueryString["COPYGUID"] != null) // check there's a GUID (won't be when creating posting if this is driven as a Posting from a Template)

{

  CmsApplicationContext oAppContext = new CmsApplicationContext(); // get an application context

  // the app context is required as the HTTP context will not (probably) be in Update mode

 

  // get current NT-authenticated user

  System.Security.Principal.WindowsIdentity ident = (System.Security.Principal.WindowsIdentity) HttpContext.Current.User.Identity;

 

  // use NT user to authenticate against site

  oAppContext.AuthenticateUsingUserHandle(ident.Token, PublishingMode.Update);

 

  // get handle to posting referred to by GUID

  Posting oPosting = ((Posting) oAppContext.Searches.GetByGuid(Request.QueryString["COPYGUID"])).RevisionForDate(new DateTime(Convert.ToInt64(Request.QueryString["REVISIONTICKS"])));

 

  // get Channel object for _Historical channel

  Channel chDest = (Channel) oAppContext.Searches.GetByPath("/Channels/_Historical");

 

 

  // following code ensures that all postings in the destination channel created more than two hours ago are cleaned out (may only be 1 hour during BST because of the way 'created date' is stored for a Posting)

  foreach(Posting oCheckPosting in chDest.Postings)

  {

    if(oCheckPosting.CreatedDate < DateTime.Now.Subtract(new TimeSpan(2, 0, 0)) && oCheckPosting.Name != "_HistoricalDefault") // leave default channel page, if there

    {

      oCheckPosting.Delete();

    }

  }

 

 

  // create posting in _Historical channel

  Posting oNewPosting = chDest.CreatePosting(oPosting.Template);

 

  // set page properties for new posting

  oNewPosting.Name = "TemporaryRevisionPosting";

  oNewPosting.DisplayName = "Temporary Revision Posting";

 

  // these properties stop the temporary page from being hyperlink-followed or indexed

  oNewPosting.IsRobotFollowable = false;

  oNewPosting.IsRobotIndexable = false;

 

  // loop through placeholders on new posting

  foreach(Placeholder oPlaceholder in oNewPosting.Placeholders)

  {

    string sName = oPlaceholder.Name;

 

    if(oPosting.Placeholders[sName] != null) // check to make sure placeholder exists on original page

    {

      oPlaceholder.Datasource.RawContent = " Note: This is a HISTORICAL version. Click here to see the CURRENT version." + oPosting.Placeholders[sName].Datasource.RawContent;

    }

  }

 

  // commit all content

  oAppContext.CommitAll();

 

  // navigate away to new posting 

  Response.Redirect(oNewPosting.UrlInner); // ensure posting is navigated by GUID as many pages with same name

}

 

4)      Create a user control called “RevisionLinks.ascx” or something similar

5)      Copy the following code into the Page_Load of the user control (you’ll also need to add a using directive for Microsoft.ContentManagement.Publishing, if it’s not on the control already):

 

Literal oHyperlinks = new Literal();

 

foreach (Posting oHistoricalPostingItem in CmsHttpContext.Current.Posting.Revisions(true, false)) // iterate through historical items

{

  oHyperlinks.Text = oHyperlinks.Text + "" + oHistoricalPostingItem.DisplayName + " on " + oHistoricalPostingItem.RevisionDate.ToString() + "
";

}

 

this.Controls.Add(oHyperlinks);

 

6)      Drag-and-drop the user control on any template where you want to be able to view and click-through to the older revisions.

7)      Try it out by viewing a posting that uses that template!

 

What should happen is that the user control renders out a list of hyperlinks of older versions. When clicked, those hyperlinks take the user to the RevisionHistory.aspx page, which creates a new posting based on the correct template and then copies across all placeholder data from the older revision to the new posting. The RevisionHistory.aspx page then redirects to the new posting. The redirect is a server redirect and so the user won’t even see it happen.

 

Note that the most recent revision in the history link will actually be the current version. Note also that there is a crucial limitation with this technique – the posting is shown based on the current version of the template. The out-the-box Web Author revision history suffers from exactly the same limitation. It shouldn’t be a problem though, as long as there’s a policy to create a new template whenever anything more than a cosmetic change is required, rather than editing and saving over the old one.

 

There’s some more trickery in the code, like on-the-fly cleaning out of old temporary postings, but the code is commented so it should make sense.

 

Tags:

MCMS

Comments

4/6/2009 9:47:34 PM #

Dan,

I hope you can find my response here. Your article is very valuable to read.

Now I got a question in my current work (revision history in MCMS).

Can you suggest me about native CMS API names which are used for Comparing inner HTML contents?

I appreciate your help.


Joseph

Joseph |

Powered by BlogEngine.NET 1.5.0.7
Theme by Interakting

Interakting

A full service digital agency offering online strategy, design and usability, systems integration and online marketing services that deliver real business benefits and ensure your online objectives are met.

Calendar

<<  July 2010  >>
MoTuWeThFrSaSu
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

View posts in large calendar