A Guide on Creating Sitecore Host Plugins

Sitecore Host is a common platform for all Sitecore services, introduced in Sitecore 9.1. 

(Please read the documentation for more details about the platform)

Several Sitecore products on this platform have been using microservices architecture already (such as Sitecore Identity and Universal Tracker), so developers can already use Sitecore Host platform to move parts of the solution outside the Sitecore site context into lightweight and fast .NET Core microservices. You can extend a service (like here), but I was more interested in moving some code outside the Sitecore instance codebase. Having a more effective scaling was one of the reasons to do that, because sometimes the data processing doesn’t require Sitecore context and consumes a lot of CPU resources on CM/CD instances. With Sitecore Host, we can easily have multiple application instances running in Docker and processing data in parallel (ok, there are some difficulties, but we will be able to do this smoothly very soon for sure).

An important thing about Sitecore Host is that it is a standalone .NET Core application with as few Sitecore relations as possible, with no relation to Sitecore, actually. We need this relation if we want to use Sitecore Host as a processing unit for a Sitecore solution. And Sitecore already has a nice tool for such communication - Message Bus. Luckily, it is based on Rebus), which we can use in our plugin!

Let’s start with a regular Sitecore Host plugin creation in our favourite IDE. e need a new .netstandard2.0 project and the first package to reference is “Sitecore.Framework.Runtime.Build”t is not a regular package, we need to edit the project file and add it as an SDK:

<sc.variable name="defaultLinkDatabaseConnectionStringName" value="core">
<Project Sdk="Microsoft.NET.Sdk">
   <Sdk Name="Sitecore.Framework.Runtime.Build" Version="1.1.0" />
   </sc.variable>

This package will help to generate a nuget package for the Sitecore Host plugin. For example, it will create “Sitecore.Plugin.manifest” file for us. It is possible to specify several parameters for it in the project file, such as 

<sc.variable name="defaultLinkDatabaseConnectionStringName" value="core">
<PropertyGroup>
   <SitecorePluginName>Sitecore.MessageBus</SitecorePluginName>
 </PropertyGroup>
 </sc.variable>

See https://docs.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2017 for details.

I also added a couple of other packages, see https://github.com/danlr/SitecoreHost.MessageBus.Plugin/blob/master/src/Sitecore.MessageBus.Plugin/Sitecore.MessageBus.Plugin.csproj 

Rebus supports several transports (https://github.com/rebus-org/Rebus/wiki/ITransport), including MS SQL Server and Azure Service Bus. I use SqlServer here because Sitecore uses it.

Rebus.ServiceProvider provides an easy way to configure Rebus in .NET Core application with a default DI container.

Now we add “ConfigureSitecore.cs” class - an entry point for a plugin. Three important methods to define are:

  1. Constructor “public ConfigureSitecore(ILogger<ConfigureSitecore> logger, ISitecoreConfiguration configuration, other injected params...)”, a good point to load the configuration from a config file. 

  2. ConfigureServices “public void ConfigureServices(IServiceCollection services)“ where we register and configure services.

  3. Configure application “public void Configure(IApplicationBuilder app)”.

As a minimum requirement, we need a connection string to Rebus database and some kind of mapping messages by type to a queue. For the sake of simplicity, we will have only one message type and one queue, so lets add a config file:

<sc.variable name="defaultLinkDatabaseConnectionStringName" value="core">
<?xml version="1.0" encoding="utf-8"?>
<Settings>
 <Sitecore>
     <MessageBus>
         <SqlConnection>
             <ConnectionString>[messaging connection string]</ConnectionString>
             <QueueName>SitecoreHost_Queue</QueueName>
         </SqlConnection>
     </MessageBus>
 </Sitecore>
</Settings>
</sc.variable>

https://github.com/danlr/SitecoreHost.MessageBus.Plugin/blob/master/src/Sitecore.MessageBus.Plugin/sitecore/Sitecore.MessageBus.Plugin/config/Sitecore.MessageBus.Plugin.xml 

I just took “messaging” connection string from my Sitecore instance, but note that Rebus will need ‘CREATE TABLE’ permission because it will create a table per queue.

Now we can add a class for storing plugin settings, load settings in constructor, initialize Rebus and subscribe to specific message type:

https://github.com/danlr/SitecoreHost.MessageBus.Plugin/blob/master/src/Sitecore.MessageBus.Plugin/ConfigureSitecore.cs

We can have a list of handlers per message type, just define a class implementing IHandleMessages<TMessage> in the project

https://github.com/danlr/SitecoreHost.MessageBus.Plugin/blob/master/src/Sitecore.MessageBus.Plugin/Messaging/TestHandler.cs and do not forget to register it:

services.AutoRegisterHandlersFromAssemblyOf<TestHandler>();

Subscription can be implemented in a line of code:

<sc.variable name="defaultLinkDatabaseConnectionStringName" value="core">
public void Configure(IApplicationBuilder app)
        {
            app.UseRebus(async bus => await bus.Subscribe());
…
</sc.variable>

Now our plugin can get messages from Sitecore Message Bus and handle them. Let’s test this somehow.

Here comes “SitecoreCommand”, built on McMaster.Extensions.CommandlineUtils (https://natemcmaster.github.io/CommandLineUtils/ ). It allows to extend Sitecore Host CLI in an elegant way. Create a class with a couple of methods:

<sc.variable name="defaultLinkDatabaseConnectionStringName" value="core">
[Command("mb-test")]
    public class TestMessageBusConnection : SitecoreCommand
    {
        public TestMessageBusConnection(IConsole console, ISitecoreConfiguration configuration)
        {
            ...
        }

        [Argument(0, Name = nameof(Message), Description = "Text to send")]
        public string Message { get; set; }

        public override Task OnExecuteAsync(CommandLineApplication app)
        {
             ...
             return Task.FromResult(0);
        }
    }
</sc.variable>

https://github.com/danlr/SitecoreHost.MessageBus.Plugin/blob/master/src/Sitecore.MessageBus.Plugin/Commands/TestMessageBusConnection.cs

Unfortunately, the package “Sitecore.Framework.Runtime.Commands” supports injection of any services starting only from version 4.1,so, for now, we will initialize Rebus in the constructor using “BuiltinHandlerActivator”. But, nevertheless, we can run our command and send a message to the Message Bus:

Immediately after publishing a message, we can see a line in Sitecore Host log file from the  handler. The message is consumed and removed from the SQL Server Database.