Rebuilding My Blog with Contentful and ASP.NET Core

Introduction

I "recently" (ahem, about a year ago) decided it was time to rebuild my blog. The design was starting to feel a little dated, and I also wanted an opportunity to experiment with building a site using a headless CMS.

I chose Contentful as the content platform. It offers a generous free tier and seemed like a great opportunity to put my (fairly) recent Contentful certification to good use. I’ve also always enjoyed working with the platform, so it felt like a natural choice for the project.

The new blog is built using a fairly simple stack:

  • Contentful – headless CMS for managing content and images

  • ASP.NET MVC (.NET 10) – the front-end website

  • Azure App Service – hosting and deployment

In this post I’ll walk through the rebuild process, including content modelling in Contentful, migrating the existing articles, implementing webhooks, improving the site design, and fixing a number of performance issues identified by Lighthouse.

The Previous Solution (and Its Problems)

The previous version of the blog was built using ASP.NET MVC on the .NET Framework (~4.x). It was a fairly traditional monolithic application, combining both the content editing interface and the public website in the same codebase.

The site was hosted on Azure App Service and used a SQL Azure database to store content. At the time I even built functionality to define custom content types and fields so that articles could be structured rather than just stored as raw HTML.

Developers will be developers…

While the site performed reasonably well thanks to .NET output caching, the editing experience was, to put it politely, painful.

There were also some architectural drawbacks. Because the content editing functionality lived inside the same public-facing application, it increased the potential attack surface. That said, judging from the number of 404 requests in the logs, most automated scanners seemed convinced the site was running WordPress!

Choosing the New Stack

For the new platform I decided to use Contentful as the CMS. I recently completed a Contentful certification and wanted to apply what I had learned on a real project. The platform also offers a free tier, making it ideal for small personal projects like this blog.

Another reason was that I enjoy working with the product. The UI is fast and simple, and the content modelling approach fits well with how I like to structure content.

For the front-end application I decided to stay within the .NET ecosystem, using ASP.NET MVC on .NET 10. It's a platform I'm familiar with, and it felt like a good opportunity to see how well it works with a headless CMS such as Contentful. Using .NET with Contentful isn’t as common as JavaScript-based stacks, which made the experiment even more interesting.

Headless architectures are becoming more common across the industry. Rebuilding my blog seemed like the perfect opportunity to build a small site using modern architectural patterns.

Content Modelling in Contentful

The free tier of Contentful allows up to 25 content types. This is juuust enough for a small site like my blog where there are only a few page types. In practice this constraint turned into an interesting design challenge: finding the right balance between flexibility, ease of editing, and keeping the total number of content types as low as possible.

One example of this was the menu structure. Rather than creating separate content types for header navigation, footer links, and other menus, I tried to design a single flexible menu content type that could support all these scenarios.

One place where I resorted to a "not ideal" content type was in my sidebar. I wanted to keep everything content editable (no more code changes for each new article written...). This meant a content type with quite a few fields to specify all the different images, links and content.

Were I not constrained here, I would have used a more component-based approach. This would involve splitting into several smaller content types.

Development with the Contentful .NET SDK

Contentful has a .NET SDK. The source code is open-source and is on GitHub: contentful.net. This repo is the codebase for two nuget packages:

You can see a few other packages under their NuGet profile here: https://www.nuget.org/profiles/Contentful.

A point of confusion

Why do I labour these points? Well there is a NuGet package called "contentful.net" which is not authored by Contentful, though it's quite hard to tell because this unofficial NuGet profile uses the Contentstack logo! In fairness, the GitHub repo of this package does state that it is now deprecated and there is an official version of the API.

Some more confusion

The other slight bump in the road in terms of building latest .NET core apps is that the sample documentation is targeted towards the older .NET core versions where there would be both a Program.cs and a Startup.cs. This was the typical convention with ASP.NET Core 1.0 - 5.0. Fortunately it still works fine with latest .NET versions (I'm using 10) and in fact the code wire-up is even easier now.

Since this article is already getting quite long, I will probably create a separate code-focused article later detailing some of the techniques I used in this project.

Content Migration

After copying a few articles by hand, I realized I needed a semi-automated system for this task. With fewer than 100 pages, I wanted something quick to develop, easy to test, and simple to improve.

Even though my previous blog used a SQL Azure DB, I chose the old site as the source for content migration. The database structure made it hard to read records for each page due to its relational setup.

My approach involved screen scraping, starting with a simple process:

  • Download my site's sitemap.xml to get all available URLs.

  • Manually copy and paste the article URLs into a CSV file (easy once opened in Excel).

  • Create a LINQPad (C#) script to read the CSV, request each URL, and save them as HTML files.

  • Move the first HTML file into a new "processing" folder.

  • Write another LINQPad query using contentful.csharp and HtmlAgilityPack NuGet packages. This script loops through the "processing" folder, reads each HTML file, and loads it into a HtmlDocument object. From there, I can easily query HTML elements like meta titles, h1 titles, and publish dates.

Using this method, I copied content page by page. I chose to manually paste the body content because automated imports could struggle with code listings, image galleries, and image wrappers.

After a few pages, I wrote another script to read the downloaded HTML files. This script extracts image sources, uploads them to Contentful, and creates "asset wrapper" entries. This technique adds useful information to images. You can see this in action right here:

Contentful Webhooks

Contentful offers a handy webhooks feature. When set up, it sends an HTTP request to a URL you choose whenever certain events happen, like publishing or updating content. This request includes context about the entry that triggered the webhook.

Handling this in ASP.NET is simple. I created a controller endpoint to receive the request. It parses the payload to get details like the entry ID and content type, then triggers the right action.

For my blog, the main use was clearing cached content after publishing an entry. Different content types need different cache behaviors. For example:

  • Publishing an article clears the article page and related listings.

  • Publishing a landing page clears only that page.

  • Updating global content (like menus) clears all cached pages.

This method lets the site use aggressive caching while ensuring new content appears right away.

Testing the webhook locally needed a small workaround. Although Contentful is great, it can’t call localhost ;-).

To test locally, I followed these steps:

  • Generate a temporary webhook endpoint using webhook.site.

  • Set up the Contentful webhook to call this endpoint.

  • Trigger the webhook by publishing content in Contentful.

  • Copy the request payload from webhook.site.

  • Use Postman to send the same request to my local webhook controller.

This let me test the controller logic without deploying the site each time.

Design Refresh

For the new design, I used Bootstrap as a base. Its responsive grid and wide range of components helped create a clean layout without much low-level CSS work.

Design isn't my strongest skill, so tools were very helpful. I started with a colour palette from the JSFiddle Colour Palette Generator. The next challenge was expanding those colours into a consistent design system.

ChatGPT was surprisingly useful here. By using the base hex colours from the palette generator, I created a wider range of lighter and darker shades. This made building a complete design system easier.

Once the initial design was set, I ran accessibility checks. Some colour combos needed adjustments to meet contrast needs. The Accessible Colours tool helped by suggesting alternative colour pairs that follow accessibility guidelines. By tweaking shades, I found combinations that looked good and passed the checks.

Deployment and Hosting

My previous blog was hosted on Azure, so I stayed with the same platform for the rebuild.

Since the new version runs on ASP.NET Core, I hosted it on a Linux-based Azure App Service instead of Windows. The migration was straightforward and caused no issues.

One perk of Linux App Service plans is that they are usually cheaper than Windows plans. They may also have faster startup and restart times, although I haven't tested this myself.

For a small project like this blog, the combination of ASP.NET Core and Azure App Service offers a straightforward and reliable hosting solution.

Final Thoughts

Rebuilding the blog was an enjoyable project. It allowed me to explore Contentful as a headless CMS, revisit architectural choices, and modernize parts of the site that needed updates.

The mix of Contentful and ASP.NET Core worked well. The Contentful API and .NET SDK made it easy to integrate content delivery into the app. The headless approach keeps content management and delivery separate.

The rebuild also let me rethink aspects like URL structure, caching strategy, and design consistency. Even for a small site, these details can greatly improve usability and performance.

The new platform feels simpler to maintain, easier to edit content, and closer to modern web application architecture.

Tagged: CMS Contentful

comments powered by Disqus