How to Keep It Stupid Simple: Use .NET Core Razor Pages

With recent improvements to the .NET platform and the ever-evolving CMS market, guidance on creating feature-rich websites is available at every turn. But what if you don’t have time for complicated tutorials and just need a modern, simple, easy-to-manage site?

Michael BerryPublished on Mar 25, 2020

With the release of .NET Core 3.x, advances in ASP.NET Core MVC and the emergence of Blazor preview, there is a lot of excitement in the .NET community. Although these improvements are wonderful, the robustness of MVC and the newness of Blazor may make some projects feel over-complicated. In addition to development complexity, accounting for CMS installations and upgrades can add extra overhead to a project. In the following article, I’ll discuss how ASP.NET Core Razor Pages and Content as a Service (CaaS) can help prevent overhead and complexity. If you’re a strong believer in the KISS principle like I am, I hope this article shows that your .NET development can be stupid simple!

Why Razor Pages?

Straightforward structure

ASP.NET Core Razor Pages takes a page-focused approach to the project structure. It colocates a page’s view and its PageModel (logic pertaining to a view) in a “Pages” directory. If you’ve modeled your content and identified that the majority of it is structured around the concept of a “page,” then Razor Pages may be the perfect framework for your project.

For example, in my sample coffee shop project, I have a lot of basic informational pages about coffee and cafes. If I wanted to make changes to the “Cafes” page, I’d navigate to ~/Pages/Cafes/Index.cshtml to edit the view or ~/Pages/Cafes/Index.cshtml/Index.cshtml.cs to edit the logic.

This single-responsibility-style structure makes finding the code for specific pages less difficult since pages are found in the “Pages” folder.


If you’ve ever used Web Forms, the above description of layout and logic being colocated should sound very familiar.  Razor Pages is sometimes viewed as the successor to Web Forms due to its structure, but it comes with modern features of .NET Core.  So if you’ve been dreading the transition from Web Forms to MVC in order to use .NET Core features, I’m sure Razor Pages will be a welcoming experience.


Routing can be very confusing or prone to errors. This being said, instead of using MVC’s less straightforward controller -> action -> view approach, default routing in a Razor Pages project uses the location of a page within the project to determine its URL.

For example, a request to “” will be handled by ~Pages/Articles/Index.cshtml and its respective .cs file, while a request to “” will be handled by Pages/Articles/Detail.cshtml and its .cs file.

Although this behavior helps simplify routing, it doesn’t prevent you from having custom routes.  For example, in my sample project, I opted to use an @page directive to append a segment to my article URLs in order to return a specific article and present a practical address to visitors.

In the Articles/Detail.cshtml view, the directive @page “{UrlPattern}” is used.

This UrlPattern value is used in the page’s logic to return content from my headless CMS’s API. We’ll discuss my choice of Content-as-a-Service/headless CMS choice later in this article, but for now, rest assured that the @page directive allows me to add a segment to a URL such as “”

In addition to page directives, Razor Pages projects can use AddRazorPages and AddRazorPagesOptions on the service collection in the Startup class. This opens up a lot of routing possibilities described in the official Microsoft documentation for Razor Pages routing. To showcase this, I used custom routing for my homepage. I wanted to organize the homepage in a subfolder similar to the other pages in my site, and I didn’t want “/Home” in the URL. This isn’t a complicated routing scenario, but you can see how this approach allows for more flexible routing.

Although I’ve focused on the page-centric structure thus far, that doesn’t mean that your project is limited to pages. Functionality that is distinct from pages or that can be reused across multiple pages can be implemented using ViewComponents. For example, in my project, I created a Components folder within Pages that contains the logic and view for displaying contact information. To use this component in my site’s footer, I just call @await Component.InvokeAsync("Contact") in my shared layout.

Although this adds a folder within Pages that isn’t directly related to any given page, this component is responsible for rendering content to pages, so it still seems sensible to have it in this location.

These are a few examples of how Razor Pages can allow developers to reap the numerous benefits of modern features provided in .NET Core while also keeping their project as simple as possible. This being said, writing code is only a fraction of the effort it takes to create a great website. How can the theme of “simplicity” extend to the content management of the project? 

Why CaaS?

For starters, what is “CaaS?” Content as a Service is an approach to creating content in a Software as a Service content management system and delivering that content over multiple channels using an API. You might be thinking, “That sounds a lot like a headless CMS...” Exactly! The CaaS approach to content creation leverages a headless CMS but also includes various services, bundles, or offerings in addition to giving editors a CMS and developers an API. For the sake of this article, you can substitute “CaaS" for “headless CMS” if it better fits your experience.

No CMS maintenance 

If you’ve ever managed an on-premise CMS or have been involved in CMS deployment and maintenance, you know that it comes with a fair amount of overhead. Installations, managing maintenance windows, doing upgrades, applying bug fixes, upgrading infrastructure... The list goes on and on. These tasks take time away from development and content creation. With a Content-as-a-Service offering, the vendor takes care of the CMS and infrastructural maintenance, which allows you to focus on development.


Even though we’re trying to keep our projects simple, the world is not a simple place. Customers have complex needs. In 2020 and beyond, customers are going to expect their content to be available on websites, mobile applications, voice assistants, and other channels. By creating your content in a system or service that is platform agnostic and can be delivered to any channel over an API, you’re ensuring the future expansion of your project to these other mediums is possible.

Structured content

In addition to the omnichannel benefits, working with CaaS makes development easier by ensuring content is structured. It’s a common practice for CaaS products to send API responses in either JSON or XML format. This streamlines the development process by making content returned from the API predictable and consistent across the project. If you’ve done proper content modeling in the early stages of development, there shouldn’t be any guessing involved when using a response from your CaaS API. Minimizing guesswork with uniform, structured content delivery will definitely make the development process smoother.


For my sample project, I chose to use as my CaaS offering. In addition to meeting all of the requirements listed in the Why CaaS? section above,’s open-source .NET SDK and supporting tools further improve the development experience.


In 2020, having a clean API is not the pinnacle of a pleasant developer experience. I’d argue that many developers leveraging an API service jump into SDK documentation almost as quickly as the base API documentation itself. With this in mind,’s .NET SDK has sensible naming conventions, extensive documentation, and dependency injection support that makes setting up the SDK and querying content a breeze. For example, other than the code related to dependency injection and strong typing, my call for retrieving an “About Us” item from is a single line of code:

This code returns a structured JSON response containing all the details about my “About Us” content item that I created in the user interface, then casts it to my AboutUs model.

Setting up the application to use dependency injection with the SDK can be accomplished in a single service registration in the Services.cs file that uses a standard configuration in an appsettings.json file:

public class Startup
    public Startup(IConfiguration configuration)
        Configuration = configuration;

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    "DeliveryOptions": {
        "ProjectId": "<Kontent_ProjectId_Value>"

Although I’ve focused on a minimal setup in the above examples, don’t worry! If your project needs more advanced functionality, the .NET SDK has lots of features and options, making it scale comfortably with increasing demands or complexity.

Model generator 

When using a Model-View-ViewModel design pattern like Razor Pages, creating and updating models can be a considerable amount of upfront and ongoing work, especially if your content creators or project managers change the content structure or requirements. To account for this, has an open-source tool that automatically generates strongly-typed models for your project. If you rely on strongly-typed models for IntelliSense, hate manually editing models, and don’t mind using a CLI tool to take on this otherwise tedious task, you’re going to love that provided the model generator for .NET projects.

Not just for developers

In addition to the development perks, a headless CMS will benefit editors and their managers too. If you’re interested in content creation features, check out this page, or you can try it out for yourself. No manuals required!


In this article, we discussed what aspects of ASP.NET Core Razor Pages make it a great framework for creating simple, but modern websites in both structure and feature sets. We also described how pairing Razor Pages with a CaaS offering like can further reduce development overhead. I hope that demonstrating my sample project showed you how we can keep it simple in 2020 and beyond!

Written by

Michael Berry

I’m the US Support Lead at In between managing an all-star team of support engineers and helping customers, I like to challenge myself with technical projects.

More articles from Michael

Feeling like your brand’s content is getting lost in the noise?

Listen to our new podcast for practical tips, tricks, and strategies to make your content shine. From AI’s magic touch to content management mastery and customer experience secrets, we’ll cover it all.

Listen now
Kontent Waves