Handling custom 404 error in Sitecore SXA

Pranay
Apr 04, 2022  ยท  914 views

If you need to raise and handle a custom 404 error, then the Sitecore's ItemResolver might not work while using SXA. Instead use the SXA's ItemNotFoundResolver. Below are the complete details.

Sitecore SXA

Default 404, 500 error pages in Sitecore SXA

Sitecore SXA module comes with custom 404 and 500 error pages out of the box. We can have a custom 404 error page configured from the Settings Items as shown below in the Settings item.

Custom 404 error page content in Sitecore SXA

Even though SXA handles the item not found cases and shows a 404 error page out of the box, there could be scenarios where you might want to throw a 404 status and show the 404 error page content. Writing a custom ItemResolver pipeline processor alone will not solve the issue. Also, your custom pipeline processors may not be triggered as SXA pipeline processors override them. So here are the steps to achieve in a SXA enabled Sitecore site.

  1. Raise a flag stating its a 404 request.
  2. Add a new processor to set the HttpStatuscode to 404 and Context item to error page
  3. Reset the context item

Note: SXA provides the namespace 'Sitecore.XA.Feature.ErrorHandling' with all the error handling implementations. Peeping into this namespace and its code will give you the details on how the ootb errors handlers are implemented. Also, most of the code examples I have provided are inspired from this namespace. So please have a deeper look into it on any similar implementations.

Sitecore SXA

1. Raising & handling custom 404 errors

There could be multiple cases where you might need to show a 404 page content. In my case, I need to return a 404 error page content when ever there is no version in a particular language with language fallback disbled. I have used the 'GetLanguageFallbackItem' to do this. When ever I need to raise a 404 error, I just set the following flag to true.

Sitecore.Context.Items[Constants.NeedsRedirect] = true;

Next, I will check if this flag is set to true in another pipeline processor and show custom 404 error page content. Below is the implementation of the same.

2. Setting 404 HttpStatuscode & redirecting to 404 error page

public class ItemNotFoundResolver: HttpRequestProcessor
{
    protected IContext Context { get; } = ServiceLocator.ServiceProvider.GetService();
    protected IErrorPageLinkProvider ErrorPageLinkProvider { get; } = ServiceLocator.ServiceProvider.GetService();
    public override void Process(HttpRequestArgs args)
    {
        if(Sitecore.Context.Items.Contains(Constants.NeedsRedirect))
        {
            RedirectToErrorPageIfExist(args);
        }
    }
    protected void RedirectToErrorPageIfExist(HttpRequestArgs args)
    {
        if (Settings.RequestErrors.UseServerSideRedirect)
        {
            Sitecore.Data.Items.Item item = ErrorPageLinkProvider.Get404ErrorPageItem();
            if (item != null)
            {
                args.ProcessorItem = item;
                Context.Item = item;
                Context.Items["httpStatus"] = HttpStatusCode.NotFound;
                args.HttpContext.Response.TrySkipIisCustomErrors = true;
            }
        }
        else
        {
            string text = ErrorPageLinkProvider.Get404ErrorPageUrl();
            if (!string.IsNullOrEmpty(text))
            {
                args.HttpContext.Response.Redirect(text);
            }
        }
    }
}

This needs to be patched after the SXA processor Sitecore.XA.Feature.ErrorHandling.Pipelines.HttpRequestBegin.ItemNotFoundResolver.

3. Setting 404 error page as context item

The Context item set in the above processor will be reset to the original context item in the pipeline . To avoid that, add the following processor which will reset it to the custom error page as context item.

public class CustomErrorPageItem : GetPageItemProcessor
{
	protected IContext Context { get; } = ServiceLocator.ServiceProvider.GetService();
	public GetCustomErrorPageContextItem(BaseClient baseClient) : base(baseClient)
	{
	}
	public override void Process(GetPageItemArgs args)
	{
		if (AbortProcessor(args)) return;
		args.Result = Context.Item;
	}
	private bool AbortProcessor(GetPageItemArgs args)
	{
			if (!Context.Items.Contains(Constants.NeedsRedirect)) return true;
			if (Context.Item == null) return true;
			if (args.Result != null) return true;
			return false;
	}
}
		

This needs to be patched before the Sitecore.Mvc.Pipelines.Response.GetPageItem.GetFromRouteUrl

.GetPageItem.GetFromRouteUrl

I hope this helps. Please do comment if you have questions.

AUTHOR

Pranay

A Software Engineer by profession, a part time blogger and an enthusiast programmer. You can find more about me here.


Post a comment




Thank you! You are now subscribed.

Sign up for our newsletter

Subscribe to receive updates on our latest posts.

Thank you! You are now subscribed.