Working with the EPiServer 7.5 Commerce API

Mari Jørgensen 06.10.2014 17.00.00

This blog post provides code samples for accessing catalog content as IContent - from basic tasks like defining the model and loading catalog content to a bit more advanced tasks. All code samples are written using example content and models/classes from the "EPiServer eCommerce Starter Kit" website. You can install this sample website when installing Commerce 7.5.

The basics - Defining the model and loading catalog content using code or id

To get the full feature set you need to connect a content type to the commerce meta class. That is done by creating a model class that inherits from the appropriate type in the EPiServer.Commerce.Catalog.ContentTypes namespace and decorate it with the CatalogContentTypeAttribute attribute.

The following types are available when creating Commerce models:

  • VariationContent - A type for variant(variation)/SKU models
  • ProductContent - A type for product models
  • BundleContent - A type for bundle models
  • PackageContent - A type for package models
  • NodeContent - A type for category/node models.
namespace EPiServer.Commerce.Sample.Models.MetaDataClasses
{
    /// FashionProductContent class, map to Fashion_Product_Class metadata class
    [CatalogContentType(GUID = "18EA436F-3B3B-464E-A526-564E9AC454C7", 
MetaClassName = "Fashion_Product_Class")] public class FashionProductContent : ProductContent { [Display(Name = "Model Number")] public virtual string Info_ModelNumber { get; set; } [Display(Name = "Facet Brand")] public virtual string Facet_Brand { get; set; } } }

Loading content using code or id

The code samples below uses several services that can be loaded from the service locator directly or injected in some way. For simplicity here is how you can load them directly using the service locator:

var ContentLoader = ServiceLocator.Current.GetInstance<IContentLoader>();
var LinksRepository = ServiceLocator.Current.GetInstance<ILinksRepository>();
var ReferenceConverter = ServiceLocator.Current.GetInstance<ReferenceConverter>();

Below is an example of loading content of type FashionProductContent:

// code of commerce ProductContent, type FashionProductContent
const string code = "Tops-Sweaters-Crew"; 
var topsSweatersCrewLink = ReferenceConverter.GetContentLink(code);
// remember to check if ContentLink is not null or empty
var topsSweatersCrewContent = ContentLoader.Get<FashionProductContent>(topsSweatersCrewLink);

// finding the same catalog content item using entry id
const int commerceEntryId = 22;
// We use the content link builder to get the contentlink to our product, 0 is version id 
var productLink = ReferenceConverter.GetContentLink(commerceEntryId, 0);
var topsSweatersCrewContent2 = ContentLoader.Get<FashionProductContent>(productLink);

// going the other way - if you have the content link but need the entry id
int entryId = ReferenceConverter.GetObjectId(productLink);

Node relation and parent/child relation

Which catalog node (category) does the product belong to in the catalog tree?
I.e. Jacket Leather Classic belongs to catalog node "Jackets-Leather":

 
// In most cases, GetNodeRelations() will only return 1 relation.
 foreach (var nodeRelation in CurrentContent.GetNodeRelations())
 {
     var catalogNode = ContentLoader.Get<NodeContent>(nodeRelation.Target);
 }     

A product often have one or several variants - for instance "Jacket Leather Classic" exists in color black size S, color black size M, color brown size S and so on. Here is how you can fetch the related VariationContent items (the different color and sizes) of type FashionItemContent:

var relationsBySource = LinksRepository.GetRelationsBySource(CurrentContent.ContentLink)
    .OfType<ProductVariation>();

List<FashionItemContent> variants = ContentLoader.GetItems(
 relationsBySource.Select(r => r.Target), LanguageSelector.AutoDetect())
                .OfType<FashionItemContent>().ToList();

Note that I prefer to use type FashionItemContent, instead of base type VariationContent, in order to get access to strongly typed properties such as Facet_Size" and "Facet_Color". 

The example above is looking at the product/variation relationship, but the same principle applies for Package/PackageEntries and Bundle/BundleEntries relationships.

Parent catalog nodes and their sort order

Lets say you need to find find all parent catalog nodes (recursively) and their sort order for a given product.
As of version 7.10 of Commerce this is not yet supported, at least not "directly".
Here are my findings:
- CurrentContent.GetNodeRelations() will only give you the nearest parent node
- LinksRepository.GetRelationsBySource(node.ContentLink) will return any linked nodes, but not the direct parent
This has been reported as a bug to support and will hopefully be fixed in later releases.
Ref: http://world.episerver.com/Modules/Forum/Pages/Thread.aspx?id=88822&epslanguage=en

A not so elegant work around is to do the following:

// finding node relations and their sort order for current catalog entry
foreach (var nodeRelation in CurrentContent.GetNodeRelations())
{
    var currentNode = ContentLoader.Get<NodeContent>(nodeRelation.Target);

    while (currentNode.ParentLink.ID > 0)
    {
        var siblings = ContentLoader.GetChildren<NodeContent>
                (currentNode.ParentLink).ToList();
        var sortOrder = siblings.FindIndex(s => s.Code == currentNode.Code);
        var nodeName = currentNode.Code ?? currentNode.Name;
        // do what you need with sortOrder and nodeName here
        currentNode = ContentLoader.Get<NodeContent>(currentNode.ParentLink);
    }
}

Note that I'm using > 0 to check if we have reached catalog root node. Preferably I would use ReferenceConverter.GetRootLink(), but that is not working.

Running this code for a book inside a catalog structure like this: 

 

would give the following result:

Books-Computer, SortOrder 1
Books, SortOrder 0
Media, SortOrder 1

I hope you have found these examples useful. Happy coding!