SaaS CMS has officially launched! Learn more now.

Maria Fel
Apr 10, 2017
  5513
(2 votes)

EpiServer Commerce 10.x. Custom Routing. SEO-FRIENDLY URL WITH CUSTOM SEGMENT

Based on

http://jondjones.com/episerver-segments-explained-registering-custom-routes-in-episerver

http://jondjones.com/episerver-7-routing-for-dummies

http://world.episerver.com/documentation/class-library/?documentId=cms/7/905519a1-ceae-2bfd-faa2-13e8a0d94eaa

http://fellow.aagaardrasmussen.dk/2016/05/15/extend-routing-in-episerver-commerce-to-support-custom-segments/

So….

I will start with task description:

Need to implement SEO - friendly url for EpiServer Commerce 10.x site. For example, we need to have target url : www.domain/v-segment/variation-code only for variations and  we would like to keep hierarchical url (www.domain/catalog/segment/product/) structure for all other pages, content.

What instruments do we have out of the EpiServer box?

First, we have HierarchicalCatalogPartialRouter out of the box for e - Commerce that provides us hierarchical url structure for Commerce and EpiServer entities. It is almost what we want.

Second, we have paradigm IPartialRouter from EpiServer (http://world.episerver.com/documentation/class-library/?documentId=cms/7/905519a1-ceae-2bfd-faa2-13e8a0d94eaa). That is not really suitable for our case, we do not want to reimplement hierarchical structure from scratch.

So, let’s start.

Let’s extend HierarchicalCatalogPartialRouter. This way I took from http://fellow.aagaardrasmussen.dk/2016/05/15/extend-routing-in-episerver-commerce-to-support-custom-segments/. I would like to add some important details to solve our task and extend it in the way to be able to work with static segments (“v-segment” in our case).

public class CustomHierarchicalCatalogRouter: HierarchicalCatalogPartialRouter {

    public const string CustomRouteSegment = "v-segment";

}

Right after we created new class and inherited it from HierarchicalCatalogPartialRouter, we have to implement several c-tors, and we are able to override following methods:

  • GetPartialVirtualPath

It is used to provide URL specific structure outside. Like provide external url.

  • RoutePartial

It is used to match current url segment to the CatalogEntity. Kind of opposite thing for  GetPartialVirtualPath.

  • FindNextContentInSegmentPair

It is used to resolve CatalogEntity due to hierarchical url structure. Basically  base.RoutePartial calls it recursively to navigate and resolve Entity. Right after  FindNextContentInSegmentPair call base.RoutePartial calls another method IsValid.

  • IsValidRoutedContent(CatalogContentBase content)

This checks if resolved object is CatalogEntity.

Mostly that is all our instruments.

Let’s go.

public override PartialRouteData GetPartialVirtualPath(CatalogContentBase content, string language,RouteValueDictionary routeValues, RequestContext requestContext){

  var variation = content as Variation;

  if (variation == null) return base.GetPartialVirtualPath(content, language, routeValues, requestContext);   

  

  return new PartialRouteData {

               BasePathRoot = RouteStartingPoint,

               PartialVirtualPath = $"{VariationRouteSegment}/{HttpUtility.UrlPathEncode(variation.RouteSegment)}"

           };

}

Here we will provide our new URL structure outside only for Variation.

Next, we have to provide support for our new URL structure for Variation. In other words be able to resolve incoming URL that contains our new segment and match it to CatalogEntity. Have a look at the code below.

Important thing here is that we no need to override FindNextContentInSegmentPair, because Variation URL has no hierarchical structure (we manage that in segmentContext.RemainingPath = string.Empty;). And we do not touch this hierarchical resolving mechanism for all other Catalog Entities.

And the latest thing in this class is to forbid resolving Variation by old hierarchical rules. For now our resolver will perfectly resolve Variation if it comes in old way like this:

www.domain/catalog/segment/product/variation-code

protected override bool IsValidRoutedContent(CatalogContentBase content)  {

    //To forbid hierarchical variation url structure:

     if (content is Variation) return false;           

     return base.IsValidRoutedContent(content);

 }

So, now we are done with Router customization. Let’s register it in Initialization module. 

var hierarchicalCatalogRouter = new CustomHierarchicalCatalogRouter(commerceService, GetStartingPoint, GetCatalogRoot(contentRepository, referenceConverter), false);

  RouteTable.Routes.RegisterPartialRouter(hierarchicalCatalogRouter);

Next thing that we have to take care of is Register our route. 

var segmentRouter = ServiceLocator.Current.GetInstance<IUrlSegmentRouter>();

  segmentRouter.RootResolver = sd => sd.StartPage;

  var parameters = new MapContentRouteParameters {

    UrlSegmentRouter = segmentRouter,

    Direction = SupportedDirection.Incoming,

    SegmentMappings = new Dictionary<string, ISegment> {{“v-segment”, new  ParameterSegment(“”v-segment)  }}

  };

  RouteTable.Routes.MapContentRoute(

  "variation_node",

  "{language}/v-segment/{node}/{action}/",

   new   {

    controller = "Variation",

    action = "Index",

   language = UrlParameter.Optional,

   },

  parameters);

Important thing here is  - segment parameters. We have to tell to Router that we are looking only for URL structure that definitely contains this particular segment “v-segment”.

Note: in current implementation we also know which controller will handle this URL.

That’s it!

Apr 10, 2017

Comments

Apr 12, 2017 11:32 AM

Great article, many thanks!

Nikolay Moskalev
Nikolay Moskalev Apr 13, 2017 05:07 PM

Thank you, Masha! Good stuff.

Farhana Abdul Jabbar
Farhana Abdul Jabbar Feb 6, 2018 12:28 PM

i still did not get how you are dealing with RoutePartial , how you are getting CatalogContentBase from uri segment (its not seo uri, its uriSegment) and to get by Sengment you need a parent node using the method contentLoader.GetBySegment 

Routing also not working if somehow i manage to get content from RoutePartial, I always get 404 page at the end.

 

Farhana Abdul Jabbar
Farhana Abdul Jabbar Feb 6, 2018 12:35 PM

Also where are you setting this , i could not understand

segmentContext.RemainingPath = string.Empty;

I am struglling to make it work but its not working for me :(

Please login to comment.
Latest blogs
Frontend Hosting for SaaS CMS Solutions

Introduction Now that CMS SaaS Core has gone into general availability, it is a good time to start discussing where to host the head. SaaS Core is...

Minesh Shah (Netcel) | Jul 20, 2024

Optimizely London Dev Meetup 11th July 2024

On 11th July 2024 in London Niteco and Netcel along with Optimizely ran the London Developer meetup. There was an great agenda of talks that we put...

Scott Reed | Jul 19, 2024

Optimizely release SaaS CMS

Discover the future of content management with Optimizely SaaS CMS. Enjoy seamless updates, reduced costs, and enhanced flexibility for developers...

Andy Blyth | Jul 17, 2024 | Syndicated blog

A day in the life of an Optimizely Developer - London Meetup 2024

Hello and welcome to another instalment of A Day In The Life Of An Optimizely Developer. Last night (11th July 2024) I was excited to have attended...

Graham Carr | Jul 16, 2024

Creating Custom Actors for Optimizely Forms

Optimizely Forms is a powerful tool for creating web forms for various purposes such as registrations, job applications, surveys, etc. By default,...

Nahid | Jul 16, 2024

Optimizely SaaS CMS Concepts and Terminologies

Whether you're a new user of Optimizely CMS or a veteran who have been through the evolution of it, the SaaS CMS is bringing some new concepts and...

Patrick Lam | Jul 15, 2024