Friendly Error Pages in Umbraco 9
In this article, we will look at how to set up friendly error pages in Umbraco 9.
Page Not Found - 404 Error Page
In Version 8 and previous versions of Umbraco, the simplest way to set up a 404 page was to add it to the umbracoSettings.config
file as shown here. When it comes to Umbraco 9, this config file no longer exists. As a matter of fact, all the XML-based config files have been replaced by JSON-based appsettings.json
file, embracing the ASP.NET Core configuration. To set up 404 error pages in Umbraco, you can make use of the Error404Collection
section in appsettings.json
. This is added to the Content
subsection as shown below. I am using the ContentKey
here but ContentId
or ContentXPath
can also be used instead of the key.
"Error404Collection": [
{
"Culture": "default",
"ContentKey": "abd58ca0-c700-47f3-b7ab-6672583572ce"
}
]
If you have language variants and wish to have a 404 page per language culture, you can specify the page per culture as shown below.
"Error404Collection": [
{
"Culture": "default",
"ContentKey": "abd58ca0-c700-47f3-b7ab-6672583572ce"
},
{
"Culture": "en-gb",
"ContentKey": "b35174d1-2be3-47df-b42d-e00a7ee27e43"
}
]
If you have language variants and a 404 page per culture is not specified, it falls back to the 404 page marked for the default culture.
You can also approach 404 pages programmatically, which can be helpful in many cases. This is done by customising the inbound pipeline in Umbraco using an IContentFinder
, more specifically IContentLastChanceFinder
. The IContentLastChanceFinder
always returns a 404 status code.
To achieve this, we first need to create a new implementation of the IContentLastChanceFinder
and return a boolean based on whether the custom 404 page was found or not.
public class PageNotFoundContentFinder : IContentLastChanceFinder
{
private readonly IDomainService _domainService;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
public PageNotFoundContentFinder(IDomainService domainService, IUmbracoContextAccessor umbracoContextAccessor)
{
_domainService = domainService;
_umbracoContextAccessor = umbracoContextAccessor;
}
public bool TryFindContent(IPublishedRequestBuilder request)
{
var allDomains = _domainService.GetAll(true).ToList();
var domain = allDomains?
.FirstOrDefault(f => f.DomainName == request.Uri.Authority
|| f.DomainName == $"https://{request.Uri.Authority}"
|| f.DomainName == $"http://{request.Uri.Authority}");
var siteId = domain != null ? domain.RootContentId : allDomains.Any() ? allDomains.FirstOrDefault()?.RootContentId : null;
if (!_umbracoContextAccessor.TryGetUmbracoContext(out var umbracoContext))
{
return false;
}
var siteRoot = umbracoContext.Content.GetById(false, siteId ?? -1);
if (siteRoot is null)
{
return false;
}
var notFoundNode = siteRoot.Children.FirstOrDefault(f => f.ContentType.Alias == Error.ModelTypeAlias);
if (notFoundNode is not null)
{
request.SetPublishedContent(notFoundNode);
}
return request.PublishedContent is not null;
}
}
This implementation then needs to be set as the ContentLastChanceFinder
using Startup.
SetContentLastChanceFinder<PageNotFoundContentFinder>()
This feature has been well documented in Umbraco Docs. The programmatic way of setting 404 pages by customising the inbound pipeline is not a new Umbraco 9 feature, it has been there in older versions of Umbraco as well.
From what I understand, the IContentLastChanceFinder
implementation takes priority over the Error404Collection
.
There is also another option, the Hot Chilli Page Not Found Manager package created by the fantastic Nik Rimington. You can install the package from Nuget and start using it straight away!
500 Error Pages
500 error pages, in my opinion, is a whole new story with .NET. It is still possible to have a web.config
with customErrors
section but then this ties up your application to use a Windows-based hosting environment.
ASP.NET Core provides an exception handling middleware for custom error handling. This can be used in the Startup
by calling the middleware and passing a error handling path which can be a static html file for your 500 errors, url to an error page in Umbraco or even a controller action. In my case, I am setting it to be a static file.
app.UseExceptionHandler("/error.html");
This static file must be located in the wwwroot
folder.
There is lots more to this feature that you can read about in the Microsoft Official Docs.
Umbraco 9 also covers us for any issues during boot up. This was a feature introduced in Umbraco 8 and is available in Umbraco 9 too. The default, pretty, boot page is available at ~/umbraco/views/errors/BootFailed.html
. However this can be customised by creating a new HTML file with the name BootFailed.html
. This file must be in the folder config/errors
in wwwroot
.
Understanding the concepts behind asynchronous messaging
Understanding the concepts behind asynchronous messaging