Hi, this is not a question. But I wanted to share a solution for a exception page that is served from Umbraco. See the solution below. Note that the exception page itself should probably be stripped of any header / footer or components because that is most likely where the exception triggered in the first place.
Because Umbraco doesn't really support a way to serve domain specific and language specific error pages out of the box. This middleware will catch any exceptions outside of the Umbraco domain (read: URL's that do not start with /umbraco/). And redirect the user to a error page that is in the CMS.
You'll still need to set-up the doctype and views yourself for this page. This is just the routing logic.
Create a new class in a folder called Middleware.
public class ExceptionMiddleware
{
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly IVariationContextAccessor _variationContextAccessor;
private readonly IDomainService _domainService;
private readonly RequestDelegate _next;
public ExceptionMiddleware(
IUmbracoContextFactory umbracoContextFactory,
IVariationContextAccessor variationContextAccessor,
IDomainService domainService,
RequestDelegate next)
{
_umbracoContextFactory = umbracoContextFactory;
_variationContextAccessor = variationContextAccessor;
_domainService = domainService;
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception)
{
HandleException(context);
}
}
private void HandleException(HttpContext httpContext)
{
var domain = _domainService.GetByUri(httpContext.Request.Host.Value);
if (domain is null)
{
return;
}
if (domain.RootContentId is not int siteId)
{
return;
}
_variationContextAccessor.VariationContext ??= new VariationContext(domain.LanguageIsoCode);
var umbracoContextReference = _umbracoContextFactory.EnsureUmbracoContext();
if (umbracoContextReference?.UmbracoContext is not UmbracoContext umbracoContext
|| umbracoContext.Content is null)
{
return;
}
var siteRoot = umbracoContext.Content.GetById(false, siteId);
var errorNode = siteRoot?.Children?.FirstOrDefault(i => i.ContentType.Alias == ErrorPage.ModelTypeAlias);
if (errorNode is null)
{
return;
}
httpContext.Response.Redirect(errorNode.Url(domain.LanguageIsoCode));
}
}
This middleware will capture any exceptions that occur in the request pipeline. And redirects the user to the error page.
This will get the root content for the current request. This is needed when you have multiple root nodes, when serving multiple websites from the same Umbraco instance.
Because middleware is outside of the scope of the Umbraco Context. We'll need to ensure a context with the context factory. One downside to this is that within the scope it does not know the variant to set for this context (for multi-lingual sites). Because of this we'll have to set it when it is null, to the domains culture.
ErrorPage.ModelTypeAlias is referring to the modelsbuilder created ErrorPage class. You can replace this with a string, but to keep things safe I prefer not to use magic strings. When changing the alias in the future, you'll get notified that the ErrorPage class does not exist anymore. Make sure you replace this with the right modelsbuilder type for your error page.
The IDomainService.GetByUri is an extension method I created, because we use this on multiple places. Feel free to copy it, or to replace the code in the middleware with the logic below:
Thanks for sharing! Here's how I ususally do it, call me old fashioned but I always made the error page a static page outside any backend pipelines just to be sure it's not caused by any errors in the CMS which would cause the error page to not show as well (and cause other problems).
Exception page served from Umbraco in V9/V10
Hi, this is not a question. But I wanted to share a solution for a exception page that is served from Umbraco. See the solution below. Note that the exception page itself should probably be stripped of any header / footer or components because that is most likely where the exception triggered in the first place.
Because Umbraco doesn't really support a way to serve domain specific and language specific error pages out of the box. This middleware will catch any exceptions outside of the Umbraco domain (read: URL's that do not start with
/umbraco/
). And redirect the user to a error page that is in the CMS.You'll still need to set-up the doctype and views yourself for this page. This is just the routing logic.
Create a new class in a folder called
Middleware
.This middleware will capture any exceptions that occur in the request pipeline. And redirects the user to the error page.
This will get the root content for the current request. This is needed when you have multiple root nodes, when serving multiple websites from the same Umbraco instance.
Because middleware is outside of the scope of the Umbraco Context. We'll need to ensure a context with the context factory. One downside to this is that within the scope it does not know the variant to set for this context (for multi-lingual sites). Because of this we'll have to set it when it is null, to the domains culture.
ErrorPage.ModelTypeAlias
is referring to the modelsbuilder createdErrorPage
class. You can replace this with a string, but to keep things safe I prefer not to use magic strings. When changing the alias in the future, you'll get notified that theErrorPage
class does not exist anymore. Make sure you replace this with the right modelsbuilder type for your error page.The
IDomainService.GetByUri
is an extension method I created, because we use this on multiple places. Feel free to copy it, or to replace the code in the middleware with the logic below:Now we'll need to add the middleware to the request pipeline. For development I want to serve the ASP.NET developer exception page.
In
Startup.Configure
(or when using minimal program, theIApplicationBuilder
). Place the following code:Just to keep things clean the
IsUmbracoDomain
on theHttpRequest
is also an extension method:Hope this helps someone!
This is fantastic! Thanks for sharing <3
Hi!
Thanks for sharing! Here's how I ususally do it, call me old fashioned but I always made the error page a static page outside any backend pipelines just to be sure it's not caused by any errors in the CMS which would cause the error page to not show as well (and cause other problems).
app.UseExceptionHandler("/error.html");
Just an alternative way :)
Probably better (and easier) for most people. In my set-up, the error page URL changes based on language. So I had to get a bit fancy :D
is working on a reply...