Last updated: Jul 23 2018

Area: Episerver Commerce, Episerver Perform Applies to versions: 2.0 and up

Using Scopes in a Multisite Installation

Note: For more information on his topic, see Multi-site support in the Personalization Native Integration for Commerce and Personalization 2.0 breaking changes.

To make the rest of this document easier to digest, we start off by defining a few central concepts.

Scope

A scope is a context in which tracking and catalog export occur. A scope contains a single Perform Engine instance and one or more websites that are communicating with that instance. Scopes are always mutually exclusive and never nested - a tracking action only occurs in a single scope. Recommendations for products belonging to a specific scope are not given for tracking actions occurring in another scope.

 Scope Description

Alias

A scope alias (referred to as “alias” from now on) is a shorthand version of the scope's name. Aliases are used as suffixes to appSettings key attribute values. The purpose of an alias is to improve the readability of configuration settings. Aliases are used in configuration settings only - they are not used in the API.

Scopeless

Settings that do not use an alias suffix are called scopeless. In earlier versions of the configuration schema, all settings are scopeless. Scopeless settings are used as a fallback if a requested setting is not defined for a specific scope. This makes the new configuration schema backwards compatible.

If asked for a valid setting for scope X, and scope X is not defined in the configuration file, the internal configuration class falls back to the corresponding scopeless setting.

Configuration

The new version of Personalization introduces a set of appSettings that let you configure several scopes within the same configuration file. The new version is backwards compatible with the old configuration scheme. So, if you do not want to use the scope feature, do not update your configuration when upgrading.

ScopeAliasMapping

ScopeAliasMapping is the only new setting in this version. But because alias is appended as a suffix to the key attribute value, you may have to modify existing keys. Please refer to this page for the list of other settings.

To define scopes that you will use, add a ScopeAliasMapping setting for each scope:

<add key="episerver:personalization.ScopeAliasMapping.[Alias]" value="[Scope]"/>

The value attribute contains the scope name. The alias should be a shorthand name to make it easier to read in the configuration file. Note that the alias value is specified as a suffix in the key attribute. When extracting the alias from the key attribute, episerver:personalization.ScopeAliasMapping. is trimmed off the beginning of the key, and the remainder is the alias. In the example above, [Alias] is the alias. The scope and alias values can be any string as long as they don't include reserved XML characters.

Together, the ScopeAliasMappings act as the master list of scopes. The aliases defined there are used to find other settings that apply to that scope. Any Personalization appSetting keys with an alias not defined as a ScopeAliasMapping are ignored.

Each ScopeAliasMapping adds a requirement that all other, required Personalization appSettings are defined using the same alias suffix. This is validated upon site initialization; an exception is thrown if any required settings are missing.

Required, Optional, and Global settings

A Personalization appSetting is either required, optional, or global. The following rules apply to each group.

  • Required settings are treated as a group – all of them must be defined for each scope. If there are no scopes, all must be defined as scopeless. Scopeless settings are allowed in parallel with scoped settings and are, in that case, used for all undefined scopes – see Fallback.
  • Optional may be defined on the scope level, scopeless level, or not at all.
  • Global settings cannot be defined per scope.

Fallback

We use a fallback scheme that works on two levels:

  • Scope fallback – At runtime, if asked to provide settings for an unknown scope (that is, a scope that has no matching ScopeAliasMapping), the fallback returns the scopeless settings if available.
  • Optional settings fallback – If an optional setting is not defined for a scope, the fallback uses the scopeless setting and, finally, the hardcoded default value.

Individual required settings do not allow for fallback due to rules that apply to them. Global settings cannot be defined per scope. Defining a global setting on the scope level does not cause an error, but the scoped value is ignored, instead falling back to the scopeless or default value.

Consider the following incomplete configuration.

<add key="episerver:personalization.ScopeAliasMapping.Alias1" value="Scope1"/>
<add key="episerver:personalization.BaseApiUrl.Alias1" value="A"/>
<add key="episerver:personalization.Site.Alias1" value="B" />
<add key="episerver:personalization.ClientToken.Alias1" value="C" />
<add key="episerver:personalization.BaseApiUrl" value="D" />
<add key="episerver:personalization.Site" value="E" />
<add key="episerver:personalization.ClientToken" value="F" />
<add key="episerver:personalization.CatalogNameForFeed" value="G"/>

 At runtime, the Site value (required) is B for Scope1, and E for all other scopes. The CatalogNameForFeed value (optional) is G for all scopes.

Default implementation

The EpiServer.Personalization package provides a default implementation of the Scope feature. This implementation assumes that each CMS site uses one Commerce catalog and one Perform Engine instance. If this setup fits your needs, you can set it up using the configuration only. If you need a more specialized setup, write custom code.

Configuration

If you have only one site that uses Personalization, use scopeless settings only. Don’t bother to define scopes.

If you need to configure several scopes, the scope names are expected to be each site's SiteDefinitionID. You can find this value in the CMS Admin mode > Config tab > Manage Websites. Starting with EPiServer.CMS.UI version 11.5.0, this value is shown in a field for each site.

 Site Definition Field

In earlier versions, get the ID from the query string in the links in the list of websites. Open each link in its own browser tab and copy the ID from the address field.

 Querystring Value

Catalog export

The default implementation iterates over all scopes registered in configuration and exports one full catalog feed per scope. On top of that, you can write custom code to filter each exported product.

CUID and SessionID storage

The default implementation stores CUID and SessionID in cookies, as it did in earlier versions. If you have a single site using Personalization, you do not need to modify this behavior. To add additional scopes, you probably need to implement your own ICookieService. See Modifying the Default Behavior for further discussion.

Identifying correct scope for tracking actions

The scope is automatically set to the SiteDefinitionID of the site that triggers the tracking action. This value is used to load the correct settings from configuration. You can override this behavior by passing the scope to the tracking method yourself. See Specifying scope for tracking actions.

Modifying the default behavior

If your installation differs from what is supported by the default implementation, you need to write custom code to fit your purposes.

Catalog export

There are several interfaces you can create custom implementations of to modify the behavior of the catalog export. The main change in the scope feature release is that the scope name for the current export is passed to all extension points. The following interfaces are of extra interest if you want to use fractions of the same catalog for different scopes

  • ICatalogItemFilter – lets you decide, for each item, if it should be included in the export for a given scope.
  • IEntryUrlService/IFeedUrlConverter – lets you define the absolute URL for a product based on a given scope.

Please see the SDK for the full list of extension points.

CUID and SessionID storage

CUIDs and SessionIDs are created by the Perform Engine. They are only valid for the Perform Engine instance that created them. This means that these values need to be siloed per scope. The default implementation stores CUID and SessionID in cookies that are bound to the current domain. This implementation covers the common scenario where no domain is shared between scopes.

If you want to support a scenario where two different scopes share a domain, write custom code to support that.

Another scenario is splitting an existing scope in two. In that case, you need to make sure that the values in existing cookies are not used for the new scope. To control how cookies are created and read for a scope, replace the default RecommendationService class implementation with your custom implementation.

Specifying scope for tracking actions

If the correct scope cannot be derived from the current SiteDefinitionID, you are responsible for determining the correct scope for each tracking action. The EPiServer.Tracking.Commerce Nuget package contains extension methods for TrackingService that let you to pass scope to the Track method.

Below is a naïve scope calculation implementation based on one of the RecommendationService class methods in Quicksilver.

public async Task<TrackingResponseData> TrackCategoryAsync(HttpContextBase httpContext, NodeContent category)
{
    if (_contextModeResolver.CurrentMode != ContextMode.Default)
    {
        return null;
    }
 
    var trackingData = _trackingDataFactory.CreateCategoryTrackingData(category, httpContext);
    AddMarketAttribute(trackingData);
 
    var scope = category.Name.StartsWith("Mens") ? "MensFashion" : "WomensFashion";
    return await _trackingService.TrackAsync(trackingData, httpContext, _contentRouteHelperAccessor().Content, scope);
}

Comments