# Best practice on handling automatic 301 redirects

**URL:** <https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434>\
**Category:** Questions\
**Created:** [April 15, 2020, 11:44am UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434 "2020-04-15T11:44:48Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![jonaskihlstrom](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/jonaskihlstrom/32/130_2.png) [@jonaskihlstrom](https://forum.litium.com/u/jonaskihlstrom)\
**Post date:** [April 15, 2020, 11:44am UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434/1 "2020-04-15T11:44:48Z")

</div>

Hi,

I would like to get some pointers/best practice on how to handle old URL´s from a previous site. The plan is to leave the url on the product but change category names and main categories. I would like to create some kind of IPageNotFoundResolver that tries to find the product in the url and automatically redirect with an 301.

Litium version: 7.4

---

<div class="post-metadata">

**Author:** ![jonaskihlstrom](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/jonaskihlstrom/32/130_2.png) [@jonaskihlstrom](https://forum.litium.com/u/jonaskihlstrom)\
**Post date:** [April 16, 2020, 6:55am UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434/2 "2020-04-16T06:55:40Z")

</div>

This is my solution so far, any thoughts?

```auto
    public bool TryGet(RouteRequestLookupInfo routeRequestLookupInfo, out RouteRequestInfo routeRequestInfo)
        {
            var result = new RouteRequestInfo();
            if (_pageByFieldType.TryFindPage(page =>
           {

               List<BaseProduct> baseProducts;

               using (var query = _dataService.CreateQuery<BaseProduct>())
               {
                   var productOldUrl = routeRequestLookupInfo.Path.Split('/').LastOrDefault() ?? "";
                   baseProducts = query
                   .Filter(p => p.Field("_url", "eq", CultureInfo.GetCultureInfo("sv-SE"), productOldUrl)).ToList();
                   
                   if(baseProducts.Count > 0)
                   {
                       var productUrl = _urlService.GetUrl(baseProducts[0]);

                       if(productUrl != null)
                       {
                           result.PageSystemId = baseProducts[0].SystemId;
                           result.DataPath = productUrl;
                           result.RedirectPermanent = productUrl;
                           return true;
                       }
                   }
                   
               }

               var url = _urlService.GetUrl(page, new PageUrlArgs(routeRequestLookupInfo.Channel.SystemId));
               if (url == null)
               {
                   return false;
               }

               result.PageSystemId = page.SystemId;
               result.DataPath = url;
               return true;
           }))
            {
                routeRequestInfo = result;
                return true;
            }

            return _parentResolver.TryGet(routeRequestLookupInfo, out routeRequestInfo);
        }

```

---

<div class="post-metadata">

**Author:** ![utku](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/utku/32/62_2.png) [@utku](https://forum.litium.com/u/utku)\
**Post date:** [April 16, 2020, 8:24am UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434/3 "2020-04-16T08:24:29Z")

</div>

Hi,  
Your approach will cause severe performance issues since it will create a direct database query for each request. The simplest way is to export old urls and import as url redirects in BO/Settings/Websites/UrlRedirects.

---

<div class="post-metadata">

**Author:** ![jonaskihlstrom](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/jonaskihlstrom/32/130_2.png) [@jonaskihlstrom](https://forum.litium.com/u/jonaskihlstrom)\
**Post date:** [April 16, 2020, 9:04am UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434/4 "2020-04-16T09:04:48Z")

</div>

Hi,

The problem with importing redirects is that we will be moving 1000 of products to new categories. It would take too long.

This is part of PageNotFoundResolverDecorator, wouldn’t it only trigger when no other page/product is found?

//Jonas

---

<div class="post-metadata">

**Author:** ![utku](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/utku/32/62_2.png) [@utku](https://forum.litium.com/u/utku)\
**Post date:** [April 16, 2020, 11:00am UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434/5 "2020-04-16T11:00:13Z")

</div>

Before we go further, what is your previous site? If you are upgraded only changing the category url is not a problem since the url history mechanism will handle that one. I’m not sure about chnaging the main category, have to test it.

---

<div class="post-metadata">

**Author:** ![jonaskihlstrom](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/jonaskihlstrom/32/130_2.png) [@jonaskihlstrom](https://forum.litium.com/u/jonaskihlstrom)\
**Post date:** [April 16, 2020, 12:49pm UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434/6 "2020-04-16T12:49:46Z")

</div>

The previous site is not a Litium site.

---

<div class="post-metadata">

**Author:** ![utku](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/utku/32/62_2.png) [@utku](https://forum.litium.com/u/utku)\
**Post date:** [April 17, 2020, 8:44am UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434/7 "2020-04-17T08:44:22Z")

</div>

You can still import all the products and categories with the old structure to Litium then change the category name, url in Litium. Then the url history will work.

I’ll be back with a suggestion for the IPageNotFoundResolver. It is better to use search instead of data query there.

---

<div class="post-metadata">

**Author:** ![utku](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/utku/32/62_2.png) [@utku](https://forum.litium.com/u/utku)\
**Post date:** [April 20, 2020, 8:31am UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434/8 "2020-04-20T08:31:32Z")

</div>

Hi again,  
Here comes a solution for your problem. You can use RoutingHelperService in your PageNotFoundResolver so that the caches are used and there will not be any performance issues.

```
using Litium.Accelerator.Caching;
using Litium.Application.Web.Routing;
using Litium.Products;
using Litium.Runtime.DependencyInjection;
using Litium.Web;
using Litium.Web.Routing;
using System;
using System.Globalization;
using System.Linq;

namespace Litium.Accelerator.Mvc.Routing
{
    [ServiceDecorator(typeof(IPageNotFoundResolver))]
    internal class PageNotFoundResolverDecorator : IPageNotFoundResolver
    {
        private readonly UrlService _urlService;
        private readonly PageByFieldTemplateCache<PageNotFoundByFieldTemplateCache> _pageByFieldType;
        private readonly RoutingHelperService _routingHelperService;
        private readonly BaseProductService _baseProductService;
        private readonly VariantService _variantService;
        private readonly IPageNotFoundResolver _parentResolver;

        public PageNotFoundResolverDecorator(
             IPageNotFoundResolver parentResolver,
             UrlService urlService,
             PageByFieldTemplateCache<PageNotFoundByFieldTemplateCache> pageByFieldType,
             RoutingHelperService routingHelperService, BaseProductService baseProductService, VariantService variantService)
        {
            _parentResolver = parentResolver;
            _urlService = urlService;
            _pageByFieldType = pageByFieldType;
            _routingHelperService = routingHelperService;
            _baseProductService = baseProductService;
            _variantService = variantService;
        }

        public bool TryGet(RouteRequestLookupInfo routeRequestLookupInfo, out RouteRequestInfo routeRequestInfo)
        {
            var result = new RouteRequestInfo();
            var url = routeRequestLookupInfo.Path.Split('/').LastOrDefault();
            var cultureInfo = CultureInfo.CurrentCulture;
            var channelSystemId = routeRequestLookupInfo.Channel.SystemId;
            BaseProduct baseProduct = null;
            var systemId = Guid.Empty;
            
            // Try to get the base product
            if (_routingHelperService.TryGetBaseProduct(url, cultureInfo, out systemId))
            {
                baseProduct = _baseProductService.Get(systemId);
            }

            if (baseProduct == null && _routingHelperService.TryGetVariant(url, cultureInfo, out systemId))
            {
                var variant = _variantService.Get(systemId);
                baseProduct = _baseProductService.Get(variant.BaseProductSystemId);
            }

            // Try to get the base product via url history
            if (baseProduct == null && _routingHelperService.TryGetProductHistoryUrl(cultureInfo, channelSystemId, url, out systemId, out bool isVariant))
            {
                if (isVariant)
                {
                    var variant = _variantService.Get(systemId);
                    baseProduct = _baseProductService.Get(variant.BaseProductSystemId);
                }
                else
                {
                    baseProduct = _baseProductService.Get(systemId);
                }
            }

            // Base product is found. Permanent redirect the correct url
            if (baseProduct != null)
            {
                result.RedirectPermanent = _urlService.GetUrl(baseProduct, new ProductUrlArgs(channelSystemId));
                routeRequestInfo = result;
                return true;
            }

            if (_pageByFieldType.TryFindPage(page =>
           {
               var url = _urlService.GetUrl(page, new PageUrlArgs(channelSystemId));
               if (url == null)
               {
                   return false;
               }

               result.PageSystemId = page.SystemId;
               result.DataPath = url;
               return true;
           }))
            {
                routeRequestInfo = result;
                return true;
            }

            return _parentResolver.TryGet(routeRequestLookupInfo, out routeRequestInfo);
        }
    }
}
```

---

<div class="post-metadata">

**Author:** ![system](https://canada1.discourse-cdn.com/flex030/uploads/litium/original/1X/12eddac3b8b661de1db86af10ac8151b571e6fb9.png) [@system](https://forum.litium.com/u/system)\
**Post date:** [May 18, 2020, 8:31am UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434/9 "2020-05-18T08:31:33Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.

---

<div class="post-metadata">

**Author:** ![patric.forsgard](https://yyz2.discourse-cdn.com/flex030/user_avatar/forum.litium.com/patric.forsgard/32/10_2.png) [@patric.forsgard](https://forum.litium.com/u/patric.forsgard)\
**Post date:** [January 4, 2022, 10:38am UTC](https://forum.litium.com/t/best-practice-on-handling-automatic-301-redirects/1434/10 "2022-01-04T10:38:45Z")

</div>

Even that it is possible in Litium 7 to use `Litium.Web.Routing.IPageNotFoundResolver` to find and make the redirection the `Litium.Web.Routing.IUrlRedirectResolver` is more suitable for that purpose and need to be used from Litium 8.
