C# - Purge Cached Files In Cloudflare Using the API

Published on

I, like many others use Cloudflare for my website.cEssentially all web requests to https://andyp.dev are proxied via Cloudflare's servers.

This comes with some benefits, one of the main one's being that static resources such as Javascript and CSS files can be cached and served from Cloudflare's servers instead of mine. This reduces the load on my server and the amout of consumed bandwidth. While at the same time (hopefully) improving the page load times for users like you.

Why Purge The Cache

You can configure the amount of time that Cloudflare instructs a visitors browser to cache files from the web portal. The browser should then cache the served static resources from your site offline, for the specified amount of time. So if your Cache TTl is set to 1 hour and a user re-visits a page within the hour, the browser won't need to contact Cloudflare or your server to download the static Javascript, CSS and images.

Cloudflare cache times

I recently worked on a project that required a bunch .jpg files to be cleared from the cache every time they were updated from a CMS. You can clear files from the cache via the Cloudflare web portal, however this is time consuming and the people uploading the file's won't neseserily have access to the portal.

clear cloudflare files

Purging The Cache

I decided to code a method that would clear the file from the cache when it is updated.

Prerequsits

  • You need to get an API get from Cloudflare before this will work.
  • I'm using Newtonsoft.Json to handle the JSON request/response. You will need to add the Newtonsoft.Json Nuget package to your project.
  • My example was written in C# using .NET Core 3.1.

The Code

You'll find the code I used below.

        /// <summary>
        /// Forward request to cloudflare
        /// </summary>
        /// <param name="url"></param>
        private static bool SendPurgeRequest(List<string> urls)
        {
            // Initializations
            var key = "Enter Your Key Here";
            var zoneId = "Enter Your Zone Id Here";
            var baseUrl = "https://api.cloudflare.com/client/v4/zones/";
            CloudflarePurgeResponse purgeResponse = null;

            // Create HttpWebRequest
            HttpWebRequest purgeRequest = WebRequest.CreateHttp($"{baseUrl}{zoneId}/purge_cache");
            purgeRequest.Method = "POST";
            purgeRequest.ContentType = "application/json";
            purgeRequest.Headers.Add("Authorization", "Bearer " + key);

            #region Create list of Files for Submission In The Structure The Response Requires
            CloudflareFileInfo fileInfo = new CloudflareFileInfo
            {
                Files = urls
            };

            byte[] data = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(fileInfo));

            purgeRequest.ContentLength = data.Length;

            using (Stream fileStream = purgeRequest.GetRequestStream())
            {
                fileStream.Write(data, 0, data.Length);
                fileStream.Flush();
            }
            #endregion


            using (WebResponse response = purgeRequest.GetResponse())
            {
                using (StreamReader purgeStream = new StreamReader(response.GetResponseStream()))
                {
                    string responseJson = purgeStream.ReadToEnd();

                    if (!string.IsNullOrEmpty(responseJson))
                        purgeResponse = JsonConvert.DeserializeObject<CloudflarePurgeResponse>(responseJson);
                }
            }

            if (purgeResponse.Success)
                return true;

            return false;
        }

And these are the Models that i've placed in a separate file.

        public class CloudflareFileInfo
        {
            [JsonProperty("files")]
            public List<string> Files { get; set; }
        }

        public class CloudflareZone
        {
            [JsonProperty("id")]
            public string Id { get; set; }

            [JsonProperty("type")]
            public string Type { get; set; }

            [JsonProperty("name")]
            public string Name { get; set; }

            [JsonProperty("content")]
            public string Content { get; set; }

            [JsonProperty("proxiable")]
            public bool Proxiable { get; set; }

            [JsonProperty("proxied")]
            public bool Proxied { get; set; }

            [JsonProperty("ttl")]
            public int Ttl { get; set; }

            [JsonProperty("priority")]
            public int Priority { get; set; }

            [JsonProperty("locked")]
            public bool Locked { get; set; }

            [JsonProperty("zone_id")]
            public string ZoneId { get; set; }

            [JsonProperty("zone_name")]
            public string ZoneName { get; set; }

            [JsonProperty("modified_on")]
            public DateTime ModifiedOn { get; set; }

            [JsonProperty("created_on")]
            public DateTime CreatedOn { get; set; }
        }

        public class CloudflarePurgeResultInfo
        {
            [JsonProperty("page")]
            public int Page { get; set; }

            [JsonProperty("per_page")]
            public int PerPage { get; set; }

            [JsonProperty("count")]
            public int Count { get; set; }

            [JsonProperty("total_count")]
            public int TotalCount { get; set; }
        }

        public class CloudflarePurgeResponse
        {
            [JsonProperty("result")]
            public CloudflareZone Result { get; set; }

            [JsonProperty("success")]
            public bool Success { get; set; }

            [JsonProperty("errors")]
            public IList<object> Errors { get; set; }

            [JsonProperty("messages")]
            public IList<object> Messages { get; set; }

            [JsonProperty("result_info")]
            public CloudflarePurgeResultInfo ResultInfo { get; set; }
        }

The Explanation

The method requires you to pass in a list of strings. You will also need to enter your API key and Cloudflare Zone Id here.

        var key = "Enter Your Key Here";
        var zoneId = "Enter Your Zone Id Here";

You'll notice that the method then creates a HttpWebRequest and serializes the list of URL's into JSON.

After forwarding the request to the Cloudflare API, the method then deserializes the result before returning either a true or false result based on the response from the API.


Article Categories: # c# # cloudflare
Date Published: Mar 14, 2020

About

A tech blog by Andy P. I talk about coding, enterprise software development, tech, games design & other things that interest me.

Signup To The Newsletter

I try to post a new interesting article every saturday.

IT Asset Management

Our friends at AssetPad are building a complete online solution for managing the IT assets within your organisation. With barcodes and documentation tools.