This post is a second post after https://vimvq1987.com/2016/03/episerver-commerce-routing-internals-part-1/ . The third part in the series can be found here: https://vimvq1987.com/2016/03/redirecting-your-product-urls-in-episerver-commerce/. (I know, I should have published the post in the right order.) They are all excerpts from my book – Pro Episerver Commerce.
The hierarchical approach:
This “new” approach (today it’s not new anymore, perhaps we can call it newer?) was introduced in Commerce 7.5 to make the routing of Catalog contents inline with CMS content. The core concept of this approach is to reflect the structure of contents to the structure of the Uri, for the discoverability. With SEO Uri approach, customers will never know how to get to the parent node, to see the other items in same category. With the partial routing, they can. To allow that, every catalog content has a piece of information – RouteSegment. This is saved in CatalogItemSeo as UriSegment, but is hidden for editing in Commerce Manager
RouteSegment is also supposed to be unique, but only within its sibling. Same as SEO Uri, RouteSegment is generated by UniqueSeoGenerator, but by another method:
public virtual string GenerateUriSegment(string name, bool includeRandomToken)
It works pretty similiar with GenerateSeoUri, except without extension part. How it works HierarchicalCatalogPartialRouter implements ICommerceRouter, which itself inherit from IPartialRouter<Tcontent, Trouteddata>, IPartialRouter has two methods for incoming and ongoing URL:
PartialRouteData GetPartialVirtualPath(TRoutedData content, string language, RouteValueDictionary routeValues, RequestContext requestContext);
object RoutePartial(TContent content, SegmentContext segmentContext);
For incoming URL, the router will parse the URL from the left to the right in RoutePartial. The first segment is supposed to match the “root content” (not the RootContent, but the configured root) – and the next segment is supposed to match the RouteSegment of one of the children of the content match the previous segment, recursively. If a content matches the entire route, it’ll be returned. For outgoing, GetPartialVirtualPath will build the URL form right to left. Starting with the content is being routed, it’ll append the RouteSegment of its parent content to the left of the URL, until it reach the root content. HierarchicalCatalogPartialRouter has three important parameters to pass to its constructor:
- RouteStartingPoint, which is a Func<ContentReference>. It is supposed to return a ContentReference to the starting point of the route. If you call CatalogRouteHelper.MapDefaultHierarchialRouter(RouteCollection routes, bool enableOutgoingSeoUri), it’ll be the ContentReference.StartPage (aka SiteDefinition.StartPage). Because this is a Func, it’ll be evaluated everytime an URL being routed, then it’s really dynamic. If you have multiple start pages, it can detect the language the customer is on, and use the right segment. If you set the Shortcut setting for your start page, it can use that, too. Just remember to use a fast Func, otherwise it’ll be hit bad.
- CommerceRoot – if you call CatalogRouteHelper.MapDefaultHierarchialRouter(RouteCollection routes, bool enableOutgoingSeoUri), it’ll be the “true” Commerce Root, but you are not limited by that. You can construct an instance of HierarchicalCatalogPartialRouter which takes a CatalogContentBase and then register it directly. This can be done in your initialization module:
var referenceConverter = ServiceLocator.Current.GetInstance<ReferenceConverter>();
var contentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
//Assuming you want to use your only catalog
var commerceRootContent = contentLoader.GetChildren<CatalogContent>(referenceConverter.GetRootLink()).First();
//RegisterPartialRouter is an extension from EPiServer.Web.Routing
RouteTables.Routes.RegisterPartialRouter(new HierarchicalCatalogPartialRouter(startingPoint, commerceRootContent, enableOutgoingSeoUri));
This is useful in case you want to hide parts of your catalog structure – because it might be sensitive or boring to show it to customers. For example, using the default CommerceRoot means your catalog RouteSegment will be included in the url, like this: http://<your-site>/en/departmental-catalog/Departments/Fashion/
If you have only on catalog and don’t want it to be shown, simply point it to your catalog. Your URL will appear to be http://<your-site>/en/Departments/Fashion/ only.
Of course, nothing prevent you from pointing your RouteStartingPoint to a category, if you want to. In this example, I can set the Departments category to be the RouteStartingPoint and remove it from the URL.
- enableOutgoingSeoUri, which is a boolean – if it’s true, then HierarchicalCatalogPartialRouter will work with SEO URI instead. Any hierarchical url which matches a catalog content will be redirected to its SEO URI.