Episerver: How to change a content's Modified date programmatically

Published on – Tags:

When migrating content from another platform to Episerver, I wanted to set a specific datetime for each content's Modified date (Saved property). Sounds simple, but it was possible only by using Episerver's internal, undocumented API. Let me tell you how to do it and how I found the solution.

(Tested only on EPiServer.CMS versions 11.14.0 and 11.19.0.)

Table of contents

How to do it

First, here's the code:

using EPiServer.Framework;
using EPiServer.DataAccess.Internal;

// ...

// Update the "Modified" datetime.
// A hacky solution that uses Epi's internal, undocumented, possibly unstable API.
// Tested to work with EPiServer.CMS 11.14.0 and 11.19.0.
ContextCache.Current[ContentSaveDB.UseIChangeTrackingSavedKey] = new object();
(content as IChangeTrackable).Saved = data.PublishedAt;
(content as IChangeTrackable).SetChangedOnPublish = true;

And here's a rough explanation:

  1. Use Episerver's internal ContentSaveDB API to change an internal setting (or something like that – I don't really know what's going on since the internal API is internal and undocumented).
  2. Set the content's Saved property to your desired datetime value. (Yes, the Saved property is the correct one even though we are modifying the Modified date. There's no Modified property.)
  3. Set the content's SetChangedOnPublish property to true or the new value of the Saved property won't take effect. (Yes, it's SetChanged* and not "SetSaved*" which doesn't even exist. I guess naming things is difficult.)
  4. That's it! Now publish the content or do whatever you were doing.

But before you go, remember this:

The code might stop working when you do any NuGet package updates since the API that you are using is internal and thus unsupported. From the ContentSaveDB class's documentation:

Unsupported INTERNAL API! Not covered by semantic versioning; might change without notice.

Is this a good idea?

Not really, but do you have any better ideas?

In my case, I was migrating content from another platform (Contentful, but it doesn't really matter) to Episerver. After I was done, I didn't need the code anymore, so it didn't really matter that I was using an internal, undocumented, possibly unstable API.

You too probably shouldn't use this hacky method in any long-living code.

Should this be even possible?

Well, that's a funny question since according to Episerver's support page "Cannot programmatically set modified date" from October 2017, this shouldn't be possible. From the page:

It is not possible to set the modified date to a specific date programmatically.

The date can only be changed by setting the SetChangedOnPublish property to true and then publish the page. This will in turn trigger an update of the modified date in the database. So it will set the date to the same one as when you publish the page.

How I found the solution

"Oh, damn," I thought to myself after reading the Episerver's support page. But fortunately I didn't give up just yet.

After googling a bit more, I found a GitHub gist by Kim Gunnarsson from April 2016. (Funnily, the gist was created 1.5 years before the Episerver's support page.)

The following lines of code from the gist are relevant, the first line being the most important:

EPiServer.Framework.ContextCache.Current[EPiServer.DataAccess.ContentSaveDB.UseIChangeTrackingSavedKey] = new object();

var clone = page.CreateWritableClone();
clone.Saved = clone.StartPublish;
clone.SetChangedOnPublish = true;

The gist is currently 4.5 years old and thus didn't work out of the box for me – I was using EPiServer.CMS version 11.14.0 and soon version 11.19.0. But this did work:

EPiServer.Framework.ContextCache.Current[EPiServer.DataAccess.Internal.ContentSaveDB.UseIChangeTrackingSavedKey] = new object();
(content as IChangeTrackable).Saved = data.PublishedAt;
(content as IChangeTrackable).SetChangedOnPublish = true;

I.e. the ContentSaveDB class has been changed into an internal class at some point.

The first line can be simplified into this with proper using statements:

using EPiServer.Framework;
using EPiServer.DataAccess.Internal;

ContextCache.Current[ContentSaveDB.UseIChangeTrackingSavedKey] = new object();

Finally, you may want to slap a comment saying that this is a hacky solution. Behold, we ended up with the code that I already presented to you at the very beginning:

using EPiServer.Framework;
using EPiServer.DataAccess.Internal;

// ...

// Update the "Modified" datetime.
// A hacky solution that uses Epi's internal, undocumented, possibly unstable API.
// Tested to work with EPiServer.CMS 11.14.0 and 11.19.0.
ContextCache.Current[ContentSaveDB.UseIChangeTrackingSavedKey] = new object();
(content as IChangeTrackable).Saved = data.PublishedAt;
(content as IChangeTrackable).SetChangedOnPublish = true;

Hmm, did someone say this isn't possible? Ha, checkmate!