SaveAction.Save | SaveAction.ForceCurrentVersion doesn't change Changed, but does touch ChangedBy

PLACE FOR BLOG

  • Home
  • /
  • Blogs
  • /
  • marija's blog
  • / SaveAction.Save | SaveAction.ForceCurrentVersion doesn't change Changed, but does touch ChangedBy
SaveAction.Save | SaveAction.ForceCurrentVersion doesn't change Changed, but does touch ChangedBy

SaveAction.Save | SaveAction.ForceCurrentVersion doesn't change Changed, but does touch ChangedBy

marija

Description

In our current Intranet solution, we wanted to use blocks to implement comments. Blocks fit us really good, they implement IVersionable, IChangeTrackable (convenient for editing - then in future we could implement who edited a comment, etc.), we have a content area on the page, where we "drop" them - programmatically, ofc. This would work quite well per se when you create a comment, add it to a content area and publish the page, however, we also had a requirement to show the Changed date and ChangedBy user info on the page (available in IChangeTrackable).

Solution that doesn't fully work

Instead publishing, we thought that SaveAction.ForceCurrentVersion will do the trick. That didn't even show the comment. What has to be used instead is SaveAction.Save | SaveAction.ForceCurrentVersion:

    contentRepo.Save(writablePage, SaveAction.Save | SaveAction.ForceCurrentVersion, AccessLevel.NoAccess);

Clearing the cache for the page has to be done as well:

    DataFactoryCache.RemovePage(currentContent.ContentLink);

This did work fine, the comment was visible when added and removed, when deleted. Changed date was also fine and set to the date when it was actually changed.

However, ChangedBy was changed, so it appeared that the page was changed by someone who actually just commented on it!

Workaround

At first, I thought I could somehow tweak EPiServer's way of setting this value, but after digging deep into their code, I've seen that this is not possible.

Instead, I've implemented the following interface in my page/block types that have comments (or likes, for that matter):

  
    public interface IHasFeedback
    {
        string RealContentChangedBy { get; set; }
    }

Then, this value is ONLY changed on publishing event (since the upper actions SaveAction.Save | SaveAction.ForceCurrentVersion do not trigger the publishing/published events):

    private static void InstancePublishingContent(object sender, ContentEventArgs e)
    {
        // ...
        if (e.Content is IHasFeedback && e.Content is IChangeTrackable)
        {
            ((IHasFeedback)e.Content).RealContentChangedBy = ((IChangeTrackable)e.Content).ChangedBy;
        }
    }

Then, instead of displaying ChangedBy, we displayed RealContentChangedBy that fallback-ed to CreatedBy for the old pages.

Overview

When you need to save a comment as a block in the ContentArea on the page, but still have the proper tracking of changes for the page, make sure to follow these steps:

  1. Use SaveAction.Save | SaveAction.ForceCurrentVersion to save to content repo
  2. Flush the cache for the page
  3. Use RealContentChangedBy instead of ChangedBy for displaying latest published value

Note: There are different ways to implement comments, but they would require more effort or would be error-prone. You could create them as IContent and implement IChangeTrackable and IVersionable yourself. You could also not save them to a content area on the page, but just save them local to the page and load them in a ViewModel's content area (but then you would need know which to load, if you have more than one type or more than one "virtual" content area). But, neither of these felt really out-of-the-box and either need more development or they might cause more bugs later, which is even more expensive.

UPDATE: See: http://world.episerver.com/forum/developer-forum/-EPiServer-75-CMS/Threa...

LEAVE A COMMENT