diff --git a/13/umbraco-cms/tutorials/custom-error-page.md b/13/umbraco-cms/tutorials/custom-error-page.md index c2df632824d..5c897c8bdbd 100644 --- a/13/umbraco-cms/tutorials/custom-error-page.md +++ b/13/umbraco-cms/tutorials/custom-error-page.md @@ -35,7 +35,11 @@ The value for error pages can be: * A content item's integer ID (example: 1234) {% hint style="warning" %} -The current implementation of XPath is suboptimal and will be removed entirely in a future version. It is currently obsolete and scheduled for removal in v14. + +The current implementation of XPath is suboptimal, marked as obsolete, and scheduled for removal in Umbraco 14. The replacement for ContentXPath is [IContentLastChanceFinder](../implementation/custom-routing/README.md#last-chance-icontentfinder). + +If you have implemented XPath in previous versions and upgraded to v13 you might encounter issues with XPath. This article will be updated when we have more details on how the article should be updated. + {% endhint %} That is where the value you grabbed earlier comes in. Fill it out like so: @@ -143,7 +147,7 @@ The following steps guides you through setting up a page for internal server err * Create a `~/controllers` folder in your Umbraco web project. * Create a file in this folder, called `ErrorController.cs`. -* Add the following code to the file: +* Add the following code to the file: ```csharp using Microsoft.AspNetCore.Mvc; @@ -172,7 +176,7 @@ The following steps guides you through setting up a page for internal server err **Namespace** replace \[YOUR\_PROJECT\_NAME] by the actual project name. In Visual Studio you can use _Sync Namespaces_ from the project context menu (in _Solution Explorer_ View). {% endhint %} -* Add an entry in `appSettings.json` for the new route "Error" like so +* Add an entry in `appSettings.json` for the new route "Error" like so ```json "Umbraco": { @@ -181,6 +185,7 @@ The following steps guides you through setting up a page for internal server err "ReservedPaths": "~/app_plugins/,~/install/,~/mini-profiler-resources/,~/umbraco/,~/error/", ... ``` + * Create the redirect pages from 1. step as regular content nodes in the backoffice. They should neither appear in navigation menus or sitemaps. In this example you would create under root node `Statuscodes` with a subnode `500`. * Update `Program.cs` diff --git a/14/umbraco-cms/README.md b/14/umbraco-cms/README.md index 7bc04aec501..042541a991c 100644 --- a/14/umbraco-cms/README.md +++ b/14/umbraco-cms/README.md @@ -17,7 +17,7 @@ The new Backoffice for Umbraco CMS is scheduled for release along with Umbraco 1 #### Recommended starting points 1. [Install v14-beta](fundamentals/setup/install/preview-builds.md#installing-the-preview-build-template) -2. [Setup your development Environment ](extending-backoffice/development-flow/)followed by [Vite package setup](extending-backoffice/development-flow/vite-package-setup.md) +2. [Setup your development Environment](extending-backoffice/development-flow/)followed by [Vite package setup](extending-backoffice/development-flow/vite-package-setup.md) 3. [Creating your first extension](tutorials/creating-a-basic-website/creating-your-first-template-and-content-node.md) 4. [Creating a custom dashboard](tutorials/creating-a-custom-dashboard.md) 5. [Creating a property editor](tutorials/creating-a-property-editor/) @@ -58,3 +58,4 @@ The list will be updated as more articles have been created and updated. * [Create your first extension](tutorials/creating-your-first-extension.md) * [Creating a Custom Dashboard](tutorials/creating-a-custom-dashboard/) * [Creating a Property Editor](tutorials/creating-a-property-editor/) + * [Implementing Custom Error Pages](tutorials/custom-error-page.md) diff --git a/14/umbraco-cms/SUMMARY.md b/14/umbraco-cms/SUMMARY.md index d6b34f7875c..55797209f15 100644 --- a/14/umbraco-cms/SUMMARY.md +++ b/14/umbraco-cms/SUMMARY.md @@ -96,3 +96,4 @@ * [Adding configuration to a Property Editor](tutorials/creating-a-property-editor/adding-configuration-to-a-property-editor.md) * [Integrating context with a Property Editor](tutorials/creating-a-property-editor/integrating-context-with-a-property-editor.md) * [Integrating services with a Property Editor](tutorials/creating-a-property-editor/integrating-services-with-a-property-editor.md) +* [Implementing Custom Error Pages](tutorials/custom-error-page.md) diff --git a/14/umbraco-cms/tutorials/custom-error-page.md b/14/umbraco-cms/tutorials/custom-error-page.md index c2df632824d..efac611476d 100644 --- a/14/umbraco-cms/tutorials/custom-error-page.md +++ b/14/umbraco-cms/tutorials/custom-error-page.md @@ -1,5 +1,9 @@ # Implementing Custom Error Pages +{% hint style="warning" %} +This tutorial is a work in progress. It will be updated as the software evolves. +{% endhint %} + Umbraco is built upon Microsoft's .NET Framework and is using ASP.NET. This provides a number of options when setting up custom error pages on your website. Custom error handling might make your site look more on-brand and minimize the impact of errors on user experience. An example, a custom 404 with some helpful links (or a search function) could bring some value to the site. @@ -20,24 +24,23 @@ One way is to watch for error events and serve corresponding pages via C# code. In this method, we will use a 404 page created via the backoffice. -#### Create a 404 page in the backoffice +### Create a 404 page in the backoffice -First, create a new Document Type (though you could also use a more generic Document Type if you already have one) called Page404. Make sure the permissions are set to create it under Content. Properties on this Document Type are optional - in most cases, the 404 not found page would be static. Make sure to assign (and fill out) the template for your error page, and then create it in Content. +1. Create a new Document Type called `Page404` with the same alias. You can also use a more generic Document Type if you already have one. +2. Set the permissions to create the Document Type at the root in the Content section. +3. Properties on this Document Type are optional. In most cases, the 404 not found page would be static. +4. Assign (and fill out) the template for your error page. +5. Create the `Page404` in the Content section. -#### Set a custom 404 page in appsettings.json +### Set a custom 404 page in appsettings.json Once all of that is done, grab your published error page's ID, GUID or path and head on over to the `appsettings.json`. The value for error pages can be: * A content item's GUID ID (example: 26C1D84F-C900-4D53-B167-E25CC489DAC8) -* An XPath statement (example: //errorPages\[@nodeName='My cool error'] * A content item's integer ID (example: 1234) -{% hint style="warning" %} -The current implementation of XPath is suboptimal and will be removed entirely in a future version. It is currently obsolete and scheduled for removal in v14. -{% endhint %} - That is where the value you grabbed earlier comes in. Fill it out like so: ```json @@ -63,11 +66,7 @@ The above sample uses a GUID value. With this approach, you can set different 404 pages for different languages (cultures) - such as `en-us`, `it` etc. {% endhint %} -{% hint style="warning" %} -If you are hosting your site on Umbraco Cloud, using an XPath statement is the best approach. This is because content IDs might differ across Cloud environments. -{% endhint %} - -XPath example: +Id example: ```json { @@ -77,7 +76,7 @@ XPath example: "Error404Collection": [ { "Culture": "default", - "ContentXPath": "//errorPages[@nodeName='My cool error']" + "ContentId": 1088 } ] } @@ -86,30 +85,75 @@ XPath example: } ``` -{% hint style="info" %} -In the above XPath example `//errorPages` is the DocTypeAlias -{% endhint %} +The above example uses an integer Id value. -Id example: +### Set a custom 404 page using IContentLastChanceFinder -```json +This is an example of how you can set up a 404 error page using `IContentLastChanceFinder`. To learn more about `IContentLastChanceFinder` read the [Custom Routing](../implementation/custom-routing/README.md#last-chance-icontentfinder) article. + +Before following this example, follow the [Create a 404 page in the backoffice](#create-a-404-page-in-the-backoffice) part. This is because this example will use the `Page404` alias of the Document Type to find and display the error page. + +1. Create a new `.cs` file called `Error404Page` in your Umbraco project. + +2. Add the following code to the newly created class: + +{% code title="Error404Page.cs" lineNumbers="true" %} + +```csharp + +using Umbraco.Cms.Core.Composing; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Web; + +namespace YourProjectNamespace; + +public class Error404Page : IContentLastChanceFinder { - "Umbraco": { - "CMS": { - "Content": { - "Error404Collection": [ - { - "Culture": "default", - "ContentId": 1088 - } - ] - } - } - } + private readonly IUmbracoContextAccessor _contextAccessor; + + public Error404Page(IUmbracoContextAccessor contextAccessor) + { + _contextAccessor = contextAccessor; + } + + public Task TryFindContent(IPublishedRequestBuilder request) + { + // In the rare case that an umbracoContext cannot be build from the request, we will not be able to find the page + if (_contextAccessor.TryGetUmbracoContext(out var umbracoContext) == false) + { + return Task.FromResult(false); + } + + // Find the first notFound page at root level through the published content cache by its documentTypeAlias + // You can make this search as complex as you want, you can return different pages based on anything in the original request + var notFoundPage = umbracoContext.Content?.GetAtRoot().FirstOrDefault(c => c.ContentType.Alias == "Page404"); + if (notFoundPage == null) + { + return Task.FromResult(false); + } + + // set the content on the request and mark our search as succesfull + request.SetPublishedContent(notFoundPage); + return Task.FromResult(true); ; + } +} + +// ContentFinders need to be registered into the DI container through a composer +public class Mycomposer : IComposer +{ + public void Compose(IUmbracoBuilder builder) + { + builder.SetContentLastChanceFinder(); + } } + ``` -The above example uses an integer Id value. +{% endcode %} + +{% hint style="info" %} +If you are hosting your site on Umbraco Cloud, using `IContentLastChanceFinder` is the best approach. This is because content IDs might differ across Cloud environments. +{% endhint %} ## Errors with booting a project @@ -143,7 +187,7 @@ The following steps guides you through setting up a page for internal server err * Create a `~/controllers` folder in your Umbraco web project. * Create a file in this folder, called `ErrorController.cs`. -* Add the following code to the file: +* Add the following code to the file: ```csharp using Microsoft.AspNetCore.Mvc; @@ -172,7 +216,7 @@ The following steps guides you through setting up a page for internal server err **Namespace** replace \[YOUR\_PROJECT\_NAME] by the actual project name. In Visual Studio you can use _Sync Namespaces_ from the project context menu (in _Solution Explorer_ View). {% endhint %} -* Add an entry in `appSettings.json` for the new route "Error" like so +* Add an entry in `appSettings.json` for the new route "Error" like so ```json "Umbraco": { @@ -181,6 +225,7 @@ The following steps guides you through setting up a page for internal server err "ReservedPaths": "~/app_plugins/,~/install/,~/mini-profiler-resources/,~/umbraco/,~/error/", ... ``` + * Create the redirect pages from 1. step as regular content nodes in the backoffice. They should neither appear in navigation menus or sitemaps. In this example you would create under root node `Statuscodes` with a subnode `500`. * Update `Program.cs` @@ -202,7 +247,7 @@ else To **test this locally**, in Visual Studio replace `app.UseDeveloperExceptionPage();` by `app.UseExceptionHandler("/error");`. Otherwise you will get the default error page with stack trace etc. {% endhint %} -#### Trigger a 500 error +### Trigger a 500 error You can trigger a 500 error on your frontend by changing a Model.Value property in your template. For example, on a Document Type with a property called `test`. The way to render it in the frontend would be `Model.Value("test");` To trigger a 500 error page you can add anything after Value such as `Model.ValueTest("test");` @@ -254,4 +299,4 @@ If your code or any packages configures a custom `IContentLastChanceFinder`, the ## Handling errors in ASP.NET Core -For common approaches to handling errors in ASP.NET Core web apps, see the [Handle errors in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-6.0) article in the Microsoft Documentation. +For common approaches to handling errors in ASP.NET Core web apps, see the [Handle errors in ASP.NET Core](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/error-handling) article in the Microsoft Documentation.