Create ASP.NET Core custom rendering engine middleware to display a content-managed not found page for Experience Edge

It is well-known that the not found page is displayed whenever a user types a non-existent domain address in the browser url. Over the years, 404 pages have become creative as specified in the best 404 pages.

Sometimes the most simple things could get left-out in the process of covering some of the other complicated things. In this blog post, I cover one such scenario of displaying the content-managed not found page on the asp.net rendering host (Sitecore MVP site as example) but has to check and fetch (using GraphQL) the not found page only when a route/path doesn't exist. Thanks to Rob Earlam for explaining this issue in a concise manner and then reviewing the PR to suggest approach-2 that was finally implemented! 

Initially when I ventured to build such a simple use-case, all I could find were suggestions to use Response. Redirect or to write a Sitecore Pipeline Processor. In short, I actually couldn't find any examples to display a not found page that is compatible with the new XM Cloud/Experience Edge-related decoupled architecture. Also, since this was an issue in the MVP site, I thought it would be good exercise to get my hands dirty. As ever, this blog post covers my approach for implementing a not found page in the decoupled architecture. 

General rule of thumb for headless architecture:

First of all, here is the premise: I use the XM Cloud repo' MVP Site  for this use-case since the existing MVP Site, displays a static not found page as of now. 

Also, there is a lot of documentation/blog posts to discuss the concepts of pipeline/engine/middleware. I'm not getting into those. Some of them here for reference:


Off to our job of customising the logic for not found page implementation -

Default Rendering Pipeline/Engine/Middleware flow:


Implementation of 404 custom logic:

Although I have detailed about two implementation approaches, approach-2 is what is implemented in current site but I've juxtaposed both approaches in this blog post. 

Approach-1:

- Make a GraphQL query call to check if layout exists, if not, request for 404 item


Pros and Cons:

- Cleaner , step-by-step approach
- To and fro GraphQL calls esp., one extra GraphQL query call to check if layout exists

***********
***********

Code commit for this approach

Approach-2:

- Make original request for the item as-is and just in case of error response, request 404 item



Pros and Cons:

- Seems cumbersome but reduces code lines
- Optimistic approach, makes 404 item call only when in need
- No unnecessary GraphQL call to check if layout exists

Since approach-2 reduces multiple calls, it was implemented based on review comments.

The most important change falls here -

Custom Rendering Engine Middleware vs Default Rendering Engine Middleware:

Approach-1:


In the above code snippet, two changes to the custom middleware compared with the default:

1. Invokes the handler that checks if layout exists for the concerned path, if not, returns false, if false, displays the 404 item else the item http requested
2. Sets the proper 404 response code for the not found item

This is how the invoked handler code (for checking valid item) looks like:

Approach-2:

Just one change in the middleware since CheckLayoutExists method call within CustomGraphQlLayoutServiceHandler is totally unnecessary:

Actual Custom middleware code:

Approach-1:


Approach-2:

///////////////


//////////////

Other titbits (generic to both approaches):

So, in order to invoke the custom middleware, make this change on top of the action method - pass the typeof custom pipeline as a param:


Note that Custom Rendering Engine Pipeline must inherit Rendering Engine Pipeline:


Understandably, the custom pipeline calls the "Use" method that in turn invokes the middleware:

Actual Custom middleware plumbing within ApplicationBuilderExtensions.cs:



Store the 404 item path in appSettings.json:

Understandably, a C# property with the same name required to deserialize the above json value.

In the DefaultController.cs (MVP site), the following logic related to not found layout can be removed completely:


NotFound.cshtml that stores the static content is not needed anymore either.

Old Not found static page:


New 404 page that displays Sitecore content with 404 response code:


Note: The most important part of the development process is debugging the Visual Studio code with Docker, refer steps in Debugging with Docker section in this blog post

Comments

Popular Posts