Show Different Catalogs for Different Customer Types
With Ucommerce comes multi-channel functionality which is the ability to show different stores and catalogs with a different look and feel on different domains. Sometimes settings up multiple stores with multiple domains may be overkill. But if you still want to differentiate what different customer types see, you can do that by redirecting your customers based on your own business logic. This article will describe how to set that up.
Understanding Catalog Context
To help you know what a customer is currently browsing in your store context is exposed via SiteContext. You'll know which store, catalog, category, and product the customer is currently browsing and also what the customer has added to her basket. In these context classes, you can also set up your own business logic for what a customer is currently looking at. This is what we want to Leverage in this article. All Libraries are context-aware, which means that the libraries will adhere to what the context says - or in the end, what your business logic says.
Setting up Custom Catalog Context
For this, we need to create a new class in our Visual Studio solution. We'll start with an empty implementation where we derive from the default implementation of the
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UCommerce.Content; using UCommerce.EntitiesV2; namespace UCommerce.MasterClass.BusinessLogic.SiteContext { /// <summary> /// An example of how to override existing components in Ucommerce. /// </summary> public class ExtendedCatalogContext : UCommerce.Runtime.CatalogContext { private readonly IRepository<ProductCatalog> _productCatalogRepository; public ExtendedCatalogContext( IDomainService domainService, IRepository<ProductCatalogGroup> productCatalogGroupRepository, IRepository<ProductCatalog> productCatalogRepository, IRepository<PriceGroup> priceGroupRepository) : base(domainService, productCatalogGroupRepository, productCatalogRepository, priceGroupRepository) { _productCatalogRepository = productCatalogRepository; } } }
We could also choose to implement the interface from scratch, which is "UCommerce.Runtime.ICatalogContext". There are two reasons why we do not do that. First thing is that we do not want to change the behavior of all the context items which looks like this:
public interface ICatalogContext { UCommerce.EntitiesV2.ProductCatalogGroup CurrentCatalogGroup { get; set; } UCommerce.EntitiesV2.ProductCatalog CurrentCatalog { get; set; } UCommerce.EntitiesV2.Category CurrentCategory { get; set; } UCommerce.EntitiesV2.Product CurrentProduct { get; set; } ICollection<UCommerce.EntitiesV2.Category> CurrentCategories { get; set; } UCommerce.EntitiesV2.PriceGroup CurrentPriceGroup { get; set; } }
As we can observe it would force us to also figure out how to resolve eg. what the current product is, and what the current store is. In our example, we are only interested in changing the catalog behavior which we can do as the default implementation are virtual implemented.
This means that we can now override that specific method.
public override ProductCatalog CurrentCatalog { get { return base.CurrentCatalog } set { this.CurrentCatalog = value; } }
Now we just need to figure out what our business logic should be. Here comes reason number two why deriving from the default implementation is good. If we for some reason cannot figure out or decide what catalog to resolve, we'll just let the default implementation decide.
In our case, we want to resolve a catalog based on the customer type. Let's just go ahead and create two catalogs in the backend under our store called "private" and "public".
Now that we have those, let's resolve the catalog based on a naming convention, just to keep it simple.
public override ProductCatalog CurrentCatalog { get { //figure out the best way to find the currentCustomerType name. string currentCustomerType = GetCurrentCustomerType(); UCommerce.EntitiesV2.ProductCatalog currentProductCatalog = _productCatalogRepository.Select(x => x.Name == currentCustomerType).FirstOrDefault(); if (currentProductCatalog == null) { return base.CurrentCatalog; } return currentProductCatalog; } set { this.CurrentCatalog = value; } } protected virtual string GetCurrentCustomerType() { //logic to find the customer goes in here }
The code above is quite simple. We query a product catalog based on the name, that we need to find. Notice on line 9 that we're returning base.CurrentCatalog if we cannot find an appropriate one. This is a good pattern as we can always rely on Ucommerce to use its own logic if our custom logic fails somehow. This might give unexpected results though, so make sure the default behavior suites your needs.
All there's left to do is following the article on how to register a custom component so we make sure that our new logic is used.