Custom Partial Html flush event

Created: 20 Sep 2021, last update: 30 Jan 2022

Custom Partial Html flush event

When you have a rendering that use data from a not scalable or slow resource, like feeds. Then you can make it faster with caching. Instead of using a custom memory cache of whatever. You could also consider using Sitecore Partial Html cache. (Sitecore 10.1+) Compared to the html cache, this has the advantage that it is not completely flushed with every publish. If you are using the Partial Html cache for rendering with neither Sitecore data either then you may also need to be able to throw a flush cache event when the external data is updated.

For flushing the partial html cache you can use the save:item event as explained in Flush HTML cache on Sitecore Forms Submit. Another possibility is your own event with your own pipeline where you can also do other things.

Build a custom:flushpartialcach event.
Like the other Sitecore events like the publish:end. In addition to the event, you also need a remote version for the other Sitecore Servers.
The config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <pipelines>      <Initialize>
        <processor type="RadioPollResult.Eventing.Event, RadioPollResult"/>
      </initialize>
    </pipelines>
    <events>
      <event name="custom:flushpartialcache">
        <handler type="RadioPollResult.Eventing.PartialHtmlCacheClearSingleItem, RadioPollResult" method="OnItemEvent" resolve="true" />
      </event>
      <event name="custom:flushpartialcache:remote">
        <handler type="RadioPollResult.Eventing.PartialHtmlCacheClearSingleItem, RadioPollResult" method="OnItemEvent" resolve="true" />
      </event>
    </events>
  </sitecore>
</configuration>

You need a Subscribe to your event, therefore you can use a processor in the Initialize pipeline:

using Sitecore.Diagnostics;
using Sitecore.Eventing;
using Sitecore.Pipelines;
using System;

namespace RadioPollResult.Eventing
{
    public class Event
    {
        public void Process(PipelineArgs args)
        {
            Initialize();
        }
        public void Initialize()
        {
            var action = new Action(RaiseRemoteEvent);
            EventManager.Subscribe(action);

        }
        private static void RaiseRemoteEvent(CustomFlushPartialCacheRemoteEvent @event)
        {
            Assert.ArgumentNotNull((object)@event, nameof(@event));
            Sitecore.Events.Event.RaiseEvent("custom:flushpartialcache:remote", @event.ItemId);
        }
    }
}

The Pipeline processor for flushing a specific rendering in partial Html cache:

using Sitecore.Abstractions;
using Sitecore.Data;
using Sitecore.Diagnostics;
using Sitecore.Web;
using System;
using System.Collections.Generic;
using System.Linq;

namespace RadioPollResult.Eventing
{
    public class PartialHtmlCacheClearSingleItem
    {
        private readonly BaseSiteContextFactory _siteContextFactory;

        public PartialHtmlCacheClearSingleItem(BaseSiteContextFactory siteContextFactory)
        {
            Assert.ArgumentNotNull((object)siteContextFactory, nameof(siteContextFactory));
            this._siteContextFactory = siteContextFactory;
        }

        public void OnItemEvent(object sender, EventArgs args)
        {
            Assert.ArgumentNotNull((object)args, nameof(args));
            Guid itemId = (Guid)Sitecore.Events.Event.ExtractParameter(args, 0);
            Flush(new ID(itemId));
        }

        private void Flush(ID itemId)
        {
            var sites = GetSitesWithPartialHtml();
            foreach (SiteInfo site in sites)
            {
                var partialcache = Sitecore.Caching.CacheManager.FindCacheByName(site.Name + "[partial html]");
                if (partialcache != null)
                {
                    foreach (var key in partialcache.GetCacheKeys())
                    {
                        if (key.Contains(itemId.ToString()))
                        {
                            partialcache.Remove(key);
                        }
                    }
                }
            }
        }

        private IEnumerable GetSitesWithPartialHtml()
        {
            return this._siteContextFactory.GetSites().Where(x => x.CacheHtml && x.EnablePartialHtmlCaheClear);
        }
    }
}

As input it use an ItemId and it flushed all Renderings in the partial html cache that use this item as datasource, all language variants in all websites. The functionality is different than Sitecore own Partial Html flush that use Content dependencies. Sitecore own functionality is internal or private and therefore we cannot use it easily. So this is using own functionality, simple and specially designed for your own needs.

The remote event needs a DataContract, for serializing to the Sitecore Event queue.
The datacontract uses the ItemRemoteEventBase, although we only need the item id.

using Sitecore.Data.Eventing.Remote;
using Sitecore.Data.Items;
using System.Runtime.Serialization;

namespace RadioPollResult.Eventing 
{

    [DataContract]
    public class CustomFlushPartialCacheRemoteEvent : ItemRemoteEventBase
    {
        public CustomFlushPartialCacheRemoteEvent(Item item) : base(item)
        {
        }
    }
}

Raise the event.
With this code you can raise a custom:flushpartialcache and custom:flushpartialcache:remote

Item item = datasourceitemtoflush

Sitecore.Events.Event.RaiseEvent("custom:flushpartialcache", (object)item.ID.ToGuid());

//raise a remote event, to clear cache other servers.
defaultQueue.QueueEvent(new CustomFlushPartialCacheRemoteEvent(item), true, false);

See Poll-Sitecore-Forms on GitHub for this code implemented as save action for SitecoreForms it contains also an implentation for the item:save approch. For more about Partial Html cache and tool for Development see Sitecore partial html cache. For more about events see: Sitecore Events