Multiple catalogs: Without catalog name(s)

My previous blog posts about multiple catalogs in multiple sites setting here and here has helped one customer (hopefully more) to address their problem. They tried the approach and it works for them. Now they came back and ask if they can remove the catalog name from the URL entirely. Is that something that can be done. Fortunately, yes.

Before moving on, let’s be clear: this is obviously custom development and is not officially supported by Episerver. I.e. it’s neither tested and documented. Normally you would have to go to Expert Services for such requirement. For this blog, I provide those samples for free (you don’t even have to buy my book ūüėČ ), but remember I can only do that much. You have to test to see if it works for you (I of course do the basic testing), and if you run into problems later, I might not be able/available to help.

Now get back to the problem. Previously the router looks like this

    
protected override CatalogContentBase FindNextContentInSegmentPair(CatalogContentBase catalogContent, SegmentPair segmentPair,
        SegmentContext segmentContext, CultureInfo cultureInfo)
    {
        if (catalogContent.ContentType == CatalogContentType.Root)
        {
            CatalogContent definedCatalogContent;
            var definedCatalogLink = _contentLoader.Get(RouteStartingPoint).CatalogLink;
            if (_contentLoader.TryGet(definedCatalogLink, cultureInfo, out definedCatalogContent))
            {
                return definedCatalogContent;
            }
        }
        return base.FindNextContentInSegmentPair(catalogContent, segmentPair, segmentContext, cultureInfo);
    }

And it works great with¬†¬†http://commerceref/en/fashion/mens/mens-shoes/p-36127195/ or¬†http://commerceref/en/products/mens/mens-shoes/p-36127195/. But now they want to completely remove the catalog name from the url. They can’t make it works with¬†http://commerceref/en/mens/mens-shoes/p-36127195/.

Why? Because the router is returning the catalog for /mens/ segment. In next segment (mens-shoes), we fallback to the default implementation, which can’t find any matching content as children of that definedCatalogContent¬†.

The solution: Because we want the first-level category to appear as direct child of the catalog root, we would have to return it ourselves. Instead of returning the catalog, we return the first node that matches /mens/ segment.

        protected override CatalogContentBase FindNextContentInSegmentPair(CatalogContentBase catalogContent, SegmentPair segmentPair,
            SegmentContext segmentContext, CultureInfo cultureInfo)
        {
            if (catalogContent.ContentType == CatalogContentType.Root)
            {
                CatalogContent definedCatalogContent;
                var definedCatalogLink = _contentLoader.Get<StartPage>(RouteStartingPoint).CatalogLink;
                if (_contentLoader.TryGet<CatalogContent>(definedCatalogLink, cultureInfo, out definedCatalogContent))
                {
                    var nodes = _contentLoader.GetChildren<NodeContent>(definedCatalogLink);
                    return nodes.FirstOrDefault(n => n.RouteSegment.Equals(segmentPair.Next, StringComparison.OrdinalIgnoreCase));
                }

                return null;
            }
            return base.FindNextContentInSegmentPair(catalogContent, segmentPair, segmentContext, cultureInfo);
        }

And it just works:

Now that’s just one part of the solution. We still need to make sure outgoing URLs respect that. I’ll leave that to you, as practice.

Multiple sites: Building the outgoing URLs

In previous recipe we talked about multiple catalogs with same “UriSegment” – which we had a working implementation for incoming URL, i.e. when a customer visit a product url, we know which catalog we should choose from. But we still need to cover the generation of outgoing URL. I.e. when we link a product (For example, from a campaign page), we need to generate an URL which take the “catalog-less” pattern into account.

We need to understand how the outgoing URL is built. The hierarchical router builds the URL by the `RouteSegment` of contents. However, we want to the urls appear to have same catalog, so the `RouteSegment` part for the catalogs must be the same, regardless of the true catalogs. Because all catalogs are on same level, their `RouteSegment` must be unique – and this is enforced from Framework level (which is understandable, otherwise, how can it know which content to choose).

(more…)

Multiple catalogs with same url

This is an excerpt from my second book . The first chapter is available to read for free.

A business is having an Episerver Commerce instance with multiple sites and multiple catalogs set up. They want to make sure each site will use one catalog, and all of them will share the same url for catalog structure. So it’ll be “https://site-a.com/products/category/”, and “https://site-b.com/products/category/”. Site A and site B are using different catalogs.

Is this doable? Yes! It’s just a matter of magic with the routing. This time, we would need to do an implementation of HierarchicalCatalogPartialRouter¬†ourselves. First, let’s create a template for it:

    
public class MultipleSiteCatalogPartialRouter : HierarchicalCatalogPartialRouter
    {
        private readonly IContentLoader _contentLoader;

        public MultipleSiteCatalogPartialRouter(Func routeStartingPoint, CatalogContentBase commerceRoot, bool enableOutgoingSeoUri, IContentLoader contentLoader) 
            : base(routeStartingPoint, commerceRoot, enableOutgoingSeoUri)
        {
            _contentLoader = contentLoader;
        }
    }

(more…)

Package equivalent promotion type in Episerver Commerce

Recently we got this question on how to create package-equivalent promotion type in Episerver Commerce, from https://world.episerver.com/forum/developer-forum/Episerver-Commerce/Thread-Container/2018/2/is-there-a-built-in-group-discount/

I already recommended to use package for such purpose, because of several reasons:

  • Package is a builtin feature, and is fully supported by the framework, both on UI level and API level.
  • It has been well tested and is very reliable to use.

However in a real world implementation, it might not be easy to just add package implementation. One reason would be if you rely on an external PIM to handle your catalog. Configuring it to support package can not be trivial.

So why not try to implement a package equivalent promotion in the promotion engine, to see if it works.

(more…)

Speed up your Catalog incremental indexing

As your products are being constantly updated, you would naturally want them to be properly (and timely) indexed – as that’s crucial to have the search results that would influence your customers into buying stuffs. For example, if you just drop the prices of your products , you would want those products to appear in new price segment as soon as possible.

This should be very easy with Find.Commerce – so if you are using Find (which you should) – stop reading, nothing for you here. Things, however, can be more complicated if you are using the more “traditional” SearchProvider.

(more…)

Why you should upgrade to the latest version

I made no secret that I’m a die-hard advocate for upgrading to latest EPiServer CMS/Commerce version. There are several reasons for that, mostly from new shiny features that your businesses dearly need, new big performance improvements that your customers firmly demand.

But there is another, not so obvious reason: support.

Let me tell you a story.

This morning we received a support case from support team. A customer recently upgraded from Commerce 7.5 (Eww) to 11.7 (Yay!), things went well except they had a small problem with data displaying in Catalog UI. Some of the properties were not properly displayed, but they are still showing correct in Commerce Manager.

(more…)

World forums support vote up/down now, and what does that mean for you

I really wanted to post this in the official blog, however we don’t have a “World” blog, and this does not really fit into “Commerce blog” which we (Commerce development team) usually use for official announcements, so I have to use my personal blog instead.

If you haven’t noticed, then you can now vote up, or down a post in World forum. Thanks to the hard work of my colleagues in World development team, that feature went on live today! (Of which I’m very excited)

If you have been using StackOverflow (as as developer, you likely have), then you know the meaning of voting up and down. The idea is the same here, there are differences in the detail implementations, such as the amount of points given (or taken) from a vote up (down), but basically:

(more…)

Loading carts in a load balancing environment

UPDATE 1: Apparently¬†HttpContext.Current.Request.AnonymousID¬†already uses the cookie internally, so there might be something that makes it stop working. I’ll update when I found out.

Today we received a support ticket as customers seeing corrupted carts data being lost – line items with invalid data, duplicated line items etc. “Corrupted data” is one of the alarming words that we take very seriously, so I decided to jump on it right away.

The setup is a load balancing environment, and the problem only happens with anonymous users. However, it can be “fixed” by turning on the sticky sessions mode. So basically, instead of having sessions on the memory of a server (so sessions on server A can’t be seen by server B, and vice versa), they need a mechanism (can be a database) to share sessions between servers.

(more…)

The art of paging

No this is not really “art” – I’m just trying to have a more clickbait title. It’s more about understanding what you have at your disposal and use them for your benefits – in this case – how new SQL statement can drastically improve your performance.

In this blogpost we will look into paging feature of SQL Server. in Commerce we usually work with large set of data – millions of rows are fairly common, and it’s natural to load data by page. There is no point loading thousands, or even millions of rows in one go. First it’s not practical to display all of them. Second you’ll likely end up with an timeout exception and/or an out of memory exception. Even if you are lucky enough to get through, it’s still able to take your SQL Server instance to a knee, and transferring that much data over network will be another bottleneck for your system. So my friends, the best practice for loading data is to do it by batches, and to not load everything at once.

(more…)

Lessons learned from a “boring” Black Friday

This Black Friday, I was in a task force, ready to help high profile DXC Commerce customers to cope with a peak in traffic. It turned out to be boring – there was no moment I could be a hero and “save the day”. Things went surprisingly smooth, even for websites which were struggling with last Black Friday. I went home and was little dissatisfied, but deep down, I know it was a huge success. The hard work from us (Commerce development team), them (the partner development teams), and Managed Services has been well paid off.

Use the latest version

You have heard me saying this, and you will probably hear from me again: Please, use the latest version possible. There is no reason to stay with an old version. This is a little truth: I hurt a little deep inside whenever I read a question on world asking a question about Commerce 7.5, or even 8.x. You should be using at least 10.8 by now, if not 11.x.

(more…)