November Happy Hour will be moved to Thursday December 5th.

Loading...

Recommended reading 

Table of Contents

Introduction

EPiServer has support for context-sensitive client components. Context could for instance be the current page that the user is working with. Since components are losely coupled the context service object is responsible for handling the current context. To get hold of the current context you could simply do this:

CopyJavaScript
var contextService = epi.dependency.resolve("epi.shell.ContextService");
var currentContext = contextService.currentContext;

The context service on the client interacts with the server to resolve context for the selected page/block/entity. The actual properties on the context object depends on the type of context being displayed but a few properties are available for all context:

uriThe key uniquely identifying the entity in context.
previewUrlThe URL on which the entity can be displayed in the editing UI.
dataThe values of the entity in context.
typeThe type of data for this context. This information is derived from the uri.
idThe id of the data for this context. This information is derived from the uri.

Context on the server implements the IClientContext interface and is serialized to the client.

Example: epi.cms.contentdata Context

One context implemented in CMS is the content data context. This is an example of such a context:

CopyJavaScript
{
    "parentLink":"4",
    "customViewType":"",
    "language":"en",
    "publicUrl":"/MaintAlloy/Alloy-Track/",
    "capabilities":
    {
        "languageSettings":true,
        "securable":true,
        "dynamicProperties":true,
        "isFolder":false,
        "isPage":true,
        "contentResources":true,
        "language":true,
        "isBlock":false
    },
    "languageContext":
    {
        "isTranslationNeeded":false,
        "language":"en",
        "isPreferredLanguageAvailable":true,
        "preferredLanguage":"en",
        "reason":1,
        "warning":null,
        "hasTranslationAccess":true
    },
    "hasSiteChanged":false,
    "fullHomeUrl":"http://localhost/MaintAlloy/EPiServer/CMS/Home",
    "versionedUrl":"",
    "dataType":"epi.cms.page",
    "uri":"epi.cms.contentdata:///8_8",
    "previewUrl":"/MaintAlloy/EPiServer/CMS/Alloy-Track,,8_8/?id=8_8&epieditmode=true",
    "data":null,
    "name":"Alloy Track",
    "requestedUri":"epi.cms.contentdata:///8",
    "versionAgnosticUri":"epi.cms.contentdata:///8"
}

The class serialized to produce this client context is ContentDataContext.

Using _ContextMixin to Access Context in Components

To simplify interaction with the context it is possible implement a mix-in that provides access to the context from a component.

CopyJavaScript
define("epi/cms/component/PageVersions", [
    "epi/shell/_ContextMixin"
], function (_ContextMixin) {
    return dojo.declare("epi.cms.component.PageVersions", [_ContextMixin], {
        constructor: function(){
            dojo.when(this.getCurrentContext(), function(context){
                console.log("we have context: ", context);
            });
        }
    }
});

The _ContextMixin extends the class with a few methods:

getCurrentContext()Returns any available context or a deferred object that will resolve to the context as soon as it becomes available.
currentContextThe currently loaded context. This may be null.
contextChanged(context, callerData)Overridable method called when the context changes. Components should check that the context is not null and may look at context.type to determine whether they can work with a given context. contextChangeFailed(previousContext, callerData)Overridable method called when loading the context fails for any reason.

Changing the Current Context

If you need to change the current context this is done by publishing a message to the "/epi/shell/context/request" channel with parameters for the new context as the data. An URI parameter property is required to determine which type of context to load. Here is an example to change the current context to an EPiServer CMS ContentData object:

CopyJavaScript
var pageLink = "5_135"; //Replace with code to determine the pageLink for the page you want to change to..
var contextParameters = { uri: 'epi.cms.contentdata:///' + pageLink };
dojo.publish("/epi/shell/context/request", [contextParameters]);

Listening to Changes to the Current Context Using Subscription

Without using the _ContextMixin it is possible to subscribe to context changes using the dojo pub/sub infrastructure. If you want to react to a context change simply subscribe to the "/epi/shell/context/changed" message:

CopyJavaScript
startup: function () {
    this.subscribe("/epi/shell/context/changed", this._contextChanged);
},
_contextChanged: function (newContext) {
    if (!newContext) {
        return;
    }
    //Do something with newContext.
}

Implementing a Context Resolver on the Server

To provide context for a certain type of entities you can implement context resolver interfaces. There are two ways of providing context; resolving a known reference using URI, and querying context on a specific URL. This is an example of a context resolver that performs both these tasks:

CopyC#
/// Resolves URIs and URLs to files for the shell context service.
[ServiceConfiguration(typeof(IUrlContextResolver))]
[ServiceConfiguration(typeof(IUriContextResolver))]
public class CmsFileContextResolver : IUriContextResolver, IUrlContextResolver
{
    private VirtualPathProvider _vpp;

    public CmsFileContextResolver(VirtualPathProvider vpp)
    {
        SortOrder = 123;
        _vpp = vpp;
    }

    /// The name of the model the context contextualizes.
    public string Name
    {
        get { return "epi.cms.unifiedfile"; }
    }

    /// Resolves a page link in URI format.
    public bool TryResolveUri(Uri uri, out IClientContext instance)
    {
        instance = ResolvePath("~" + uri.LocalPath);
        return instance != null;
    }

    /// Tries to resolve an url to page context.
    public bool TryResolveUrl(Uri url, out IClientContext instance)
    {
        instance = ResolvePath(url.LocalPath);
        return instance != null;
    }

    private IClientContext ResolvePath(string path)
    {
        var file = _vpp.GetFile(path) as UnifiedFile;
        if (file == null)
        {
            return null;
        }
        return new Models.UnifiedFileContext
        {
            Uri = new Uri("epi.file.unifiedfile://" + VirtualPathUtilityEx.ToAppRelative(file.VirtualPath).TrimStart('~')),
            Data = new
            {
                file.VirtualPath,
                // ... more unifiedfile-specific data
            },
            PreviewUrl = file.VirtualPath
        };
    }

    /// Sort order among peer url resolvers.
    public int SortOrder { get; set; }
}

Querying for a New Context by URL

Context resolvers implementing the IUrlContextResolver interface are queryed when an URL is loaded in the preview frame. To programmatically change the context to the context associated with an URL publish a message. This is an example of this:

CopyJavaScript
// queries the context service for the context belonging to a URL
var contextParameters = { url: someUnknownUrl.toString() };
dojo.publish("/epi/shell/context/request", [contextParameters, { sender: this }]);
Do you find this information helpful? Please log in to provide feedback.

Last updated: Mar 21, 2013

Recommended reading