﻿#### 

Sitecore Processing Engine is a new ASP.Net Core based job of xConnect that works as a Windows service (or Azure Job). In order to run our custom code inside processing engine we need to make quite a number of configuration changes, register our custom types, inject our services, figure out how to access to xdb, etc. In this post we will review the basics of coding for Sitecore host applications (it applies to all xConnect jobs: processing engine, automation engine and indexing worker).

For our demo scenario we create custom MLNetService that will be a layer between Processing engine and Machine Learning engine.

```
public interface IMLNetService
 {
    Task<ModelStatistics> Train(string schemaName, CancellationToken cancellationToken, params TableDefinition[] tables);
        Task<IReadOnlyList<object>> Evaluate(string schemaName, CancellationToken cancellationToken, params TableDefinition[] tables);
 }

public MLNetService : IMLNetService 
{
 public async Task<ModelStatistics> Train(string schemaName, CancellationToken cancellationToken, params TableDefinition[] tables)
        {
            throw new NotImplementedException();
        }
public async Task<IReadOnlyList<object>> Evaluate(string schemaName, CancellationToken cancellationToken, params TableDefinition[] tables) {
            throw new NotImplementedException();
        }
}
```

Note: some namespaces used in the above code are located inside libraries that exist only in Processing Engine instance, you can find them here: “xconnect\_instance\App\_Data\jobs\continuous\ProcessingEngine\”. Such libraries contain “\*.ML.\*” in their names (for example Sitecore.Processing.Engine.ML.Abstractions.dll)

So how do we register custom service is Sitecore processing engine? 

Let’s see how dependency injection works in process engine and how we can pass parameters from configuration into our service:

To register our service we need to add the following xml config to “xconnect\_instance\App\_Data\jobs\continuous\ProcessingEngine\App\_Data\Config\” folder.

```
<Settings>
    <Sitecore>
        <Processing>
            <Services>
                <IMLNetService>
<Type>Demo.Foundation.ProcessingEngine.Services.MLNetService, Demo.Foundation.ProcessingEngine</Type>
                    <As>Demo.Foundation.ProcessingEngine.Services.IMLNetService, Demo.Foundation.ProcessingEngine</As>
                    <LifeTime>Transient</LifeTime>
                    <Options>
                       <TestValue>0.25</TestValue>
                    </Options>
                </IMLNetService>
            </Services>
       </Processing>
   </Sitecore>
</Settings>
```

Notice we just need to register our type in &lt;Processing/Services&gt; node, choose a lifetime (Scoped/Singleton/Transient), and also we can pass any parameters in &lt;Options&gt; node. To access these parameters in our service we need to inject Microsoft.Extensions.Configuration.IConfiguration and read these parameters (or even entire section):

```
public class MLNetService : IMLNetService
{
    private double _testValue;

    public MLNetService(IConfiguration configuration)
    {
         _testValue = configuration.GetValue<double>("TestValue");
    }
}
```

To have access to logger we need to inject generic Microsoft.Extensions.Logging.ILogger 

```
public class MLNetService : IMLNetService
{
    private double _testValue;
    private readonly ILogger<MLNetService> _logger;
    public MLNetService(IConfiguration configuration, ILogger<MLNetService> logger)
    {
             _testValue = configuration.GetValue<double>("TestValue");     _logger = logger;     _logger.LogInformation("Hello MLNetService”);
    }
}
```

(Logs are written to “xconnect\_instance\App\_Data\jobs\continuous\ProcessingEngine\App\_Data\Logs\” folder.)

To inject our MLNetService into another service we just need to include it in constructor parameters:

```
public class AnotherService
{
    private IMLNetService _mlNetService;
    public AnotherService(IMLNetService mlNetService)
    {_mlNetService  = mlNetService;
    }
}
```

Another way - to inject IServiceProvider and get our service from its scope:

```
public class AnotherService
{
    public AnotherService(IServiceProvider serviceProvider)
    {
        using (var scope = _serviceProvider.CreateScope())
        {
            using (var service = scope.ServiceProvider.GetService<IMLNetService>())
            {
        	. . .
            }
        }
    }
}
```

To access to xdb context we can just retrieve IXdbContext service from ServiceProvider:

```
using (var scope = _serviceProvider.CreateScope())
{using (var xdbContext= scope.ServiceProvider.GetService<IXdbContext>())
    {var contact = await xdbContext.GetContactAsync(...);
    }
}
```

How can we debug our code? 

Because of processing engine works as a Windows service we need to attach to Sitecore.ProcessingEngine service. To do this, we need to configure debugging in Visual Studio: open menu bar, choose **Tools &gt; Options**. In the Options dialog box, choose **Debugging &gt; Symbols**, select the **Microsoft Symbol Servers** check box.

![configure debugging in Visual Studio](https://www.brimit.com/-/media/images/blog/cortexpart1-1debug.jpg)

Then on the menu bar select Attach to Process from the Debug or Tools menu, in Processes dialog box select the “Show processes from all users” checkbox and find Sitecore.ProcessingEngine service.

![Attach debug tool in VS](https://www.brimit.com/-/media/images/blog/cortexpart1-2attach.jpg)

Now you can catch breakpoints and debug your code:

![catch breakpoints in code](https://www.brimit.com/-/media/images/blog/cortexpart1-3breakpoint.jpg)

But processing engine tasks run by the agent and it is not comfortable to wait for debugging while sleep period will be ended. As a workaround, you can create WebApi where you can trigger tasks registration and your task will start immediately. You just need to send request to your API (with Postman, browser console or any other tool):

```
public class TestСontroller: ApiController
    {
        public async Task<Guid> RegisterTasks()
        {
            var taskManager = ServiceLocator.ServiceProvider.GetService<ITaskManager>();
            ...
            var guid = await taskManager.RegisterModelTrainingTaskChainAsync(modelTrainingOptions, dataSourceOptions, TimeSpan.FromHours(1));
            
            return guid;
        }
    }
```

(More information about tasks registration you can find here “Part 4 - Workers, Options dictionary, Agents and Task Manager”(coming soon))

In response, you will see the ID of your task and you can check it in ProcessingEngineTasks database.

![ProcessingEngineTasks database](https://www.brimit.com/-/media/images/blog/cortexpart1-4database.jpg)

You can also check tasks execution processes in processing engine log. It look like:

```
[Information] Registered Distributed Processing Task, TaskId: 8faf6763-c623-45b7-a987-f08c9efc71d9, Worker: Sitecore.Processing.Engine.ML.Workers.ProjectionWorker`1[[Sitecore.XConnect.Interaction, Sitecore.XConnect, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null]], Sitecore.Processing.Engine.ML, DataSource: Sitecore.Processing.Engine.DataSources.DataExtraction.InteractionDataSource, Sitecore.Processing.Engine
[Information] Registered Deferred Processing Task, Id: c27c8eaa-efb2-42c5-b638-5357f76c3460, Worker: Sitecore.Processing.Engine.ML.Workers.MergeWorker, Sitecore.Processing.Engine.ML
[Information] Registered Deferred Processing Task, Id: bc344b9f-f22a-4074-bcef-76578d85a045, Worker: Demo.Foundation.ProcessingEngine.Workers.RfmTrainingWorker, Demo.Foundation.ProcessingEngine
[Information] TaskAgent Executing worker. Machine: BRIMIT-SBA-PC, Process: 4132, AgentId: 4, TaskId: 8faf6763-c623-45b7-a987-f08c9efc71d9, TaskType: DistributedProcessing.
[Information] TaskAgent Worker execution completed. Machine: BRIMIT-SBA-PC, Process: 4132, AgentId: 4, TaskId: 8faf6763-c623-45b7-a987-f08c9efc71d9, TaskType: DistributedProcessing.
[Information] TaskAgent Executing worker. Machine: BRIMIT-SBA-PC, Process: 4132, AgentId: 4, TaskId: c27c8eaa-efb2-42c5-b638-5357f76c3460, TaskType: DeferredAction.
[Information] TaskAgent Worker execution completed. Machine: BRIMIT-SBA-PC, Process: 4132, AgentId: 4, TaskId: c27c8eaa-efb2-42c5-b638-5357f76c3460, TaskType: DeferredAction.
[Information] TaskAgent Executing worker. Machine: BRIMIT-SBA-PC, Process: 4132, AgentId: 4, TaskId: bc344b9f-f22a-4074-bcef-76578d85a045, TaskType: DeferredAction.
[Information] RfmTrainingWorker.RunAsync
```

This post outlines some basic information you should know when working with Sitecore Processing Engine. Some additional information you can find in the official Sitecore documentation about [“Sitecore Host”](https://doc.sitecore.com/developers/91/sitecore-experience-management/en/sitecore-host.html "Sitecore Host")

Table of contents [Dive into Sitecore Cortex and Machine Learning - Introduction](https://www.brimit.com/blog/dive-sitecore-cortex-machine-learning-introduction "Intro")

Read next [Part 2 - Adding custom events, facets and models](https://www.brimit.com/blog/cortex-ml-2-adding-custom-events-facets-models "Sitecore custom events, facets and models")

##### Do you need help with your Sitecore project?

      ![](~/media/CD37043DFD1F491D8E92958A11959F75.ashx?la=en&amp;hash=D08B252DD3B41C09B588007541E5D22F)

   [VIEW SITECORE SERVICES](https://www.brimit.com/expertise/sitecore-cms)

###### Author

[!\[sergey-200\](https://www.brimit.com/-/jssmedia/feature/blogs/authors/sergey-200.jpg?h=197&amp;iar=0&amp;w=200&amp;hash=0D636570F87F1C13C39E06EB19D9DF06)
Sergey Baranov
Sitecore MVP/ Senior Sitecore Developer](https://www.brimit.com/blog/author?authors=Sergey%20Baranov)

#### More on Sitecore

[!\[How Vercel Will Help You Save Effort When Deploying Sophisticated Sitecore Projects\](https://www.brimit.com/-/jssmedia/project/brimit/blog/2024/vercel_cover-image.png)
#Guides#How-toDXPE-commerce
##### How Vercel Will Help You Save Effort When Deploying Sophisticated Sitecore Projects
Optimize and accelerate the development and deployment of complex multisite Sitecore projects.
Alexei Vershalovich on July 17, 2024](https://www.brimit.com/blog/how-vercel-will-help-you-save-effort-when-deploying-sophisticated-sitecore-projects)

[!\[Training Up Tomorrow's Sitecore MVPs: a Mentoring Success Story\](https://www.brimit.com/-/jssmedia/project/brimit/blog/2023/sitecore-mentoring---cover-image.png)
#How-toDXP
##### Training Up Tomorrow's Sitecore MVPs: a Mentoring Success Story
How to participate in the Sitecore Mentor program and help younger colleagues jump-start a career in Sitecore development.
Sergey Baranov on October 2, 2023](https://www.brimit.com/blog/training-up-tomorrows-sitecore-mvps)

[!\[Going Headless. Part 2: When a Headless CMS Is Your Best Bet (if you have Sitecore)\](https://www.brimit.com/-/jssmedia/project/brimit/blog/2022/headless/adobestock_456986731.jpg)
#How-toDXPE-commerce
##### Going Headless. Part 2: When a Headless CMS Is Your Best Bet (if you have Sitecore)
Discover how a headless CMS can benefit organizations that use Sitecore.
Daniil Raschupkin, Palina Trokhautsava on September 15, 2022](https://www.brimit.com/blog/going-headless-part-2-when-a-headless-cms-is-your-best-bet-if-you-have-sitecore)

![](https://bat.bing.net/action/0?ti=187017043&amp;tm=gtm002&amp;Ver=2&amp;mid=f8255a74-8bfc-420d-b584-df868ca93f81&amp;bo=2&amp;gtm_tag_source=1&amp;pi=0&amp;lg=en-US&amp;sw=800&amp;sh=600&amp;sc=24&amp;nwd=1&amp;tl=Sitecore%20Cortex%20and%20ML%3A%20Part%201%20-%20Creating%20Sitecore%20Processing%20Engine%20Service&amp;kw=sitecore,%20Cortex,%20Machine%20Learning,%20ML,%20%20Processing,%20%20Engine%20Service%20&amp;p=https%3A%2F%2Fwww.brimit.com%2Fblog%2Fcortex-ml-1-creating-sitecore-processing-engine-service&amp;r=&amp;lt=334&amp;evt=pageLoad&amp;sv=2&amp;asc=D&amp;cdb=AQAY&amp;rn=9951)