Extending Sitecore CMP Connector

No comments

I have been trying out Sitecore Content hub for past several weeks and I must say that I am really impressed by it – especially the level of customization that can be done. The scripting features are amazing – developers can use multiple development flows [Multiple SDK’s, REST Api’s and C# scripting] to achieve their business logics, this is something that is unseen in other SaaS based platforms.

Sitecore Content Hub

I also got a chance to try out connectors for Sitecore,

  • Sitecore Connect™ for Sitecore CMP – It is used to sync the Contents created in Content hub to Sitecore using Azure service bus and a custom mapping configuration that maps out Content hub fields with Sitecore Fields. Unlike Sitecore Connect for Sitecore DAM – it creates contents as items in Sitecore.

It makes sense to have two different connectors as CMP and DAM are two different features in Content Hub and comes with separate licensing. But I would prefer it to be a single Connector for Sitecore that can be tuned up to work on different Content Hub Entities – as each one is a separate entity, Asset being a M.Asset Entity and Content being M.Content Entity.

So the connector could be just one that can sync multiple Entities to Sitecore upon custom Entity triggers ! That’s what I have done extending CMP connector.

Of-course this could be true to other Content Hub entities as well ! This way any entity can be mapped out and can be easily synced to Sitecore allowing much more close integration.

I think I have provided a brief intro about connectors and how they work – now let’s discuss some features that I extended in connector.

1. Syncing Assets to Sitecore

The first and foremost change I did is to extend CMP connector to sync Assets from Content hub. I found the ability to choose an asset using Sitecore DAM Connect is good but it didn’t solve many use cases.

Sitecore DAM Connect : A pop-up opens up where users can search assets and select it. Upon selection, ‘Public-Link’ of asset is added to image or anchor tag based on Asset type selected.

I found the behavior of opening up all assets in a popup and adding public link is limiting a lot of business cases !

  1. Crawling assets using Sitecore Engines : Let’s say that you have a component where you need to dynamically search assets items using Sitecore query or through custom taxonomy fields – it is no more possible to do it as the assets are not present in Sitecore and thereby Search engine of Sitecore cannot crawl them. Showing assets like user manuals, brochures, white papers , catalogs along with other contents in a custom search results page will not be possible as well.
  2. Securing or limiting access of assets in a multi-site setup : This is another use where there are multiple Sitecore sites and you maintain all the assets in Content Hub but you need to limit assets to specific Sites. This can be achieved if assets are maintained in different Media library folders that are specifically created for each site. But the connector doesn’t support this as it shows up all assets and users can end up choosing assets that are not meant for specific site. [You can find how this is done in later part of this blog using Entity mapping rule for asset based on a Taxonomy ]
  3. Using Asset’s meta-data in a Sitecore component : It is again an usual case where in components are created to display not just asset but to show a few more asset related information like description, media size, thumbnails etc. Using client SDK provided by Content Hub, it is possible to retrieve them but it is much easier to get these information if it is stored as an Sitecore Media Library item.
Storing the assets in Sitecore Media Library solves all the above issues but I wanted to achieve this without having to compromise on Storage. So syncing Asset Metadata information into Sitecore Media library items and creating a custom Media processor that can process Public Link using "MediaId, Version & Transform" solves this problem ! This way Sitecore creates cache of media on it's side and from then on Media is taken care by Sitecore ! Authors can easily select the assets by browsing media library instead of having to select them through the pop-up.
CMP ContentHub DAM

Of-Course storing assets in Sitecore Media Library is not an optimal solution as it creates same copy of assets in another place and eats up storage in Sitecore instance. But not storing Media as a blob or a file in Sitecore and just storing the metadata saves a lot of storage ! During the first request, media is accessed through a custom media processor that reads the data through public link and returns it as stream. From there on, the media is served through Mediacache in Sitecore ( or a CDN if configured) – and let’s not worry about cache clearance , if an image is updated – it automatically syncs in new version Id from Content hub to Sitecore !

 public class ExternalMediaProcessor
        private string ContentHubUri
                var connectionSettings = Settings.GetConnectionString("CMP.ContentHub");
                ToConnectionDictionary(connectionSettings).TryGetValue("URI", out string contentHuburl);
                return contentHuburl;

        public IEnumerable<string> ValidMimeTypes
                var validMimetypes = Settings.GetSetting("ContentHub.ValidMimeTypes", "image/jpeg|image/pjpeg|image/png|image/gif|image/tiff|image/bmp");
                return validMimetypes.Split(new[] { ",", "|", ";" }, StringSplitOptions.RemoveEmptyEntries);

        public void Process(GetMediaStreamPipelineArgs args)
            Assert.ArgumentNotNull(args, "args");

            if (!IsValidImageRequest(args.MediaData.MimeType))
            var transForm = GetQueryOrCustomOption(Transform, args.Options.CustomOptions);
            var version = GetQueryOrCustomOption(Version, args.Options.CustomOptions);
            var mediaId = GetQueryOrCustomOption(MediaId, args.Options.CustomOptions);

            //Return in case the version or media id is missing
            if (string.IsNullOrEmpty(version) || string.IsNullOrEmpty(mediaId))
            if (args.Options.Thumbnail)
                transForm = ThumbNailTransform;
                var client = new WebClient();
                // Read image from ContentHub
                var result = client.OpenRead(string.Format(ContentHubUri + "/api/public/content/{0}?v={1}&t={2}", mediaId, version, transForm));
                if (result == null)
                var stream = new MemoryStream();
                args.OutputStream = new MediaStream(stream, args.MediaData.Extension, args.MediaData.MediaItem);
            catch (Exception ex)
                Log.Error(ex.Message, ex, this);
Above part of the code processes the request using query strings such as mid - media id , v - version id and t - transformation that corresponds to the asset.
Ex : 
Default Rendition - https://{sitecoreurl/media-url}?v=versionid&mid=mediaid
W800 Transform - https://{sitecoreurl/media-url}?v=versionid&mid=mediaid&t=w800
W320/Thumbnail - https://{sitecoreurl/media-url}?v=versionid&mid=mediaid&t=w320
W16/Icon - https://{sitecoreurl/media-url}?v=versionid&mid=mediaid&t=scIcon

You can use all the transformations configured in Content hub – very useful feature if you need to crop images and make it responsive !!

2. Rule based Entity Mapping

Next important improvement that I did is to the way in which entity mapping is done in Sitecore. If you’ve already used Sitecore CMP Connector – you must be familiar with the mapping feature, if not it is just like a config item that is used to map out,

Content hub Entity Field mapping
  • Folder Path – In which item needs to be created,
  • Template – that should be used while creating the mapped out item,
    And Field mapping that between properties in Content hub and Sitecore item fields. They are of two types,
  • Field mapping – that lets you to map out properties to Sitecore fields.
  • Relational Field Mapping – that lets you map complex field types such as taxonomies.
The entity mapping is done for each type of Entity that needs to be synced to Sitecore. I have two sample entity mapping created, one is for Asset which uses M.Asset type of Entity and other one is Blog which uses M.ContentType.Blog Entity. I have configured them using custom Entity rules that can be used to map template and folder based on properties within entities ex: let's say you've two different sites Contoso / Sample Site - and you have a taxonomy created in Content hub to associate content with site , then a rule can be applied to select folder based on the selected taxonomy. 

Let’s see the difference between out-of-box mapping vs customized rule based mapping and you’ll notice that rule based mapping can be much more beneficial to implement a lot of use cases !!

 As you can see in below image, there are couple of custom Entity Mapping Conditions and Entity Mapping Actions that can be used to create rules.
CMP Entity Mapping

These rules can be applied on both Asset and Content type entities so the folder and template is not static anymore.

This makes it much easier to apply rules based on site and to restrict contents & assets to specific target audience/site !!

3. Advanced Field Mapping using Jtokens

The CMP connector comes with a Field Mapping but it doesn’t really allow to map fields that are directly under properties. Let’s say you need to map out Content.Variant using it’s Label – then it is not possible as it is a property within Content Variant !

As the Entity Information is JSON and is processed JSON.net querying feature can be applied using Select Tokens !!

JToken based CMP Field name can be applied using PropertyName<jtoken.query> format as shown in the below image. This way you can map out complex properties to Sitecore fields !! This proved to be really useful especially for Assets.


I hope these changes can be useful to achieve your business cases using Content Hub and Sitecore ! It is one of longest blogs – thanks for reading till the end !!

References : 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.