Using Cloudflare With Kentico - Purging Cached Media Files
This month I've been writing some blog posts on why I decided to start using Cloudflare service for my website and utilising its API to allow me to purge cached files from the Cloudflare CDN on demand. Before reading further, I highly suggest perusing those posts just to put everything into context for my reasoning into using Cloudflare as well as the C# code that interacts with the API, which I will be referencing later on within this very post.
My intial Cloudflare integration evolves around serving media files more efficiently through a CDN and having the ability to refresh these files automatically as updates are made within the Kentico CMS. Cloudflare's CDN services can help cache your content across their large global network, moving static files closer to your visitor.
Based on the Page Rules I configured within the Cloudflare dashboard, I am caching all media library files served through the /getmedia/ URL path into the Cloudflare CDN. The same file will be served through the CDN until the set cache limit has expired. We need to implement functionality that will add some automation to the Kentico platform to purge the cache of a specific media library file when updated.
Add A Global Event
I created an event handler for the updating of Media library files as I wanted to get details of the file being updated by leveraging the MediaFileInfo class to access the Update.After
event.
protected override void OnInit()
{
base.OnInit();
MediaFileInfo.TYPEINFO.Events.Update.After += Update_After;
}
private void Update_After(object sender, ObjectEventArgs e)
{
MediaFileInfo fileInfo = e.Object as MediaFileInfo;
GlobalEventFunctions.PurgeMediaCache(fileInfo);
}
PurgeMediaCache() Method
The event above calls a GlobalEventFunctions.PurgeMediaCache()
method that will pass the information about the changed file ready for purging. The file URL parsed to the Cloudflare.PurgeSelectedFiles()
method needs to be exact and take into consideration how your instance of Kentico is serving media files. If Permanent URL's are being used the /getmedia/ URL needs to be constructed consisting of:
- Current domain
- File GUID
- File Name
- File Extension
Otherwise, we can just use get the file path as normal to where the media file resides.
public class GlobalEventFunctions
{
/// <summary>
/// Purges a file from the Cloudflare cache.
/// </summary>
/// <param name="fileInfo"></param>
public static void PurgeMediaCache(MediaFileInfo fileInfo)
{
bool permanentURLEnabled = SettingsKeyInfoProvider.GetBoolValue($"{SiteContext.CurrentSiteName}.CMSMediaUsePermanentURLs");
string filePath = string.Empty;
if (permanentURLEnabled)
filePath = $"{GetCurrentDomain()}/getmedia/{fileInfo.FileGUID.ToString()}/{fileInfo.FileName}{fileInfo.FileExtension}";
else
filePath = $"{GetCurrentDomain()}/{fileInfo.FilePath}";
try
{
// Get code from: https://www.surinderbhomra.com/Blog/Post/2018/11/11/Cloudflare-API-Purge-Files-By-URL-In-C
CloudflareCacheHelper cloudflareHelper = new CloudflareCacheHelper();
cloudflareHelper.PurgeSelectedFiles(new List<string> { filePath });
}
catch (Exception ex)
{
EventLogProvider.LogException("Cloudflare Purge File Cache", "CLOUDFLARE_PURGE", ex, SiteContext.CurrentSiteID, $"Purge File: {filePath}");
}
}
/// <summary>
/// Get domain from current http context.
/// </summary>
/// <returns></returns>
private static string GetCurrentDomain()
{
return $"{HttpContext.Current.Request.Url.Scheme}{Uri.SchemeDelimiter}{HttpContext.Current.Request.Url.Host}{(!HttpContext.Current.Request.Url.IsDefaultPort ? $":{HttpContext.Current.Request.Url.Port}" : null)}";
}
}
We need not consider any other scenarios, such as insert or deletion. If a file is inserted, there is nothing to purge as it's a new file that will be cached directly into in the CDN on first request and when it comes to deletion we can just wait for the cache to expire.
What's Next?
The integration I have detailed so far is just scratching the surface of what Cloudflare has to offer and will investigate further on pushing more content over to the CDN. One area, in particular, I am looking into is carrying out full page caching. You might be thinking why even bother as Kentico has pretty good caching mechanisms already in place?
Well Cloudflare has a really neat feature called "Always Online", where a cached version of a page is served if on the off chance it happens to go down or requires a reboot to install key security updates. But implementing this feature requires strict Page Rules to be setup within the Cloudflare dashboard to ensure the general workings of Kentico are not effected.