﻿#### Sitecore xConnect: Service plugin implementation

Have you ever thought about implementing a service plugin for Sitecore xConnect? You probably know that there is a lack of information on how to do that. Let’s figure it out together!

What does the service plugin mean in general? It is something like a pipeline in Sitecore which runs for each request to the xConnect and where you can hook into the following events raised by xConnect:

- Batch executed
- Batch executing
- Batch execution failed
- Operation added
- Operation completed
- Operation executing

Looking at the list above we can see two main terms: **Batch (Sitecore.XConnect.Operations.XdbOperationBatch)** and **Operation (Sitecore.XConnect.Operations.IXdbOperation)**. Each communication with xConnect happens by batches. At the same time, each batch can contain any number of operations. You can read more about batches by the following link: [Sitecore Batching](https://doc.sitecore.net/developers/xp/xconnect/xconnect-client-api/batching/index.html "Sitecore batchnig").

For example, when we search for a contact in the Experience Profile, a batch with only one **Sitecore.XConnect.Operations.XdbSearchOperation&lt;Contact&gt;** operation will be executed in xConnect.

Requesting a contact from xConnect by ContactId will initialize the batch with **Sitecore.XConnect.Web.Infrastructure.Operations.GetEntitiesOperation&lt;Contact&gt;** and **Sitecore.XConnect.Operations.GetEntityOperation&lt;Contact&gt;** operations, where the first operation represents a Direct Operation and the second one is an dependent operation.

It means that our request initializes a direct operation which will return or add some data. At the same time, a direct operation can add dependent operations for “helping” achieve their goals.

In case of creating a new contact, two batches would be launched: first Sitecore tries to retrieve contact by an identifier, then, if a contact doesn’t exist, Sitecore creates it by running the batch with four direct operations: **Sitecore.XConnect.Operations.AddContactOperation** and two **Sitecore.XConnect.Operations.SetFacetOperation&lt;TFacet&gt;** for setting data in the common facets like the PhoneNumbers, Personal, and Emails. Code below describes a contact creation process and shows where the batch executions initiates:

```
     //Creating new contact identify referenceIdentifiedContactReference reference = new IdentifiedContactReference(source, identifier);
https://www.brimit.com//Trying to retrieve contact by identifier.//At this step, the first separate batch will be launched.var contactTask = client.GetAsync(	reference,	new ContactExpandOptions(		PersonalInformation.DefaultFacetKey,		EmailAddressList.DefaultFacetKey,		PhoneNumberList.DefaultFacetKey));
Contact existingContact = await contactTask;
https://www.brimit.com//Checking if contact exists. If it is, we don't need to continue the contact creation processif (existingContact != null){	return false;}
https://www.brimit.com//Adding an identifier for new contactvar contactIdentifier = new[]{	new ContactIdentifier(source, identifier, ContactIdentifierType.Known)};
https://www.brimit.com//Creating a new contact objectContact contact = new Contact(contactIdentifier);
https://www.brimit.com//Creating a new Personal Information facet and filling a datavar personal = new PersonalInformation{	FirstName = firstName,	LastName = lastName,	Title = title};//Creating a new Phone Numbers facet and filling a datavar preferredPhoneNumber = new PhoneNumber(string.Empty, phone);var phoneNumbers = new PhoneNumberList(preferredPhoneNumber, "Work");
https://www.brimit.com//Creating a new Emails facet and filling a datavar preferredEmail = new EmailAddress(email, true);var emails = new EmailAddressList(preferredEmail, "Work");
https://www.brimit.com//The following line looks like it adds the contact. But in fact it just adds the Sitecore.XConnect.Operations.AddContactOperation operation to the current context batch.client.AddContact(contact);//Adding Sitecore.XConnect.Operations.SetFacetOperation<Sitecore.XConnect.Collection.Model.PhoneNumberList> operation to the current context batch.client.SetPhoneNumbers(contact, phoneNumbers);//Adding Sitecore.XConnect.Operations.SetFacetOperation<Sitecore.XConnect.Collection.Model.PersonalInformation> operation to the current context batch.client.SetPersonal(contact, personal);//Adding Sitecore.XConnect.Operations.SetFacetOperation<Sitecore.XConnect.Collection.Model.EmailAddressList> operation to the current context batch.client.SetEmails(contact, emails);
https://www.brimit.com//Initiating execition of the context batch.await client.SubmitAsync();
```

In general, service plugin represents a “subscriber” to xConnect events where they will be executed in the following order:

1. Operation added
2. Batch executing
3. Operation executing
4. Operation completed

The events above would be applied to each operation that adds to the batch.

1. Batch executed - the last endpoint and runs ones for the batch.
2. Batch execution failed - would be fired if something was wrong during batch execution.

At each step, you can access current operation and/or batch. Batch, at the same time, has a list of operations added to it. It allows us to control every stage of operation processing, extend it, validate, subscribe to operation events, log something and so on.

In my case, the goal was pretty simple. I needed to track and send a request to a third party API when a new contact is created. To achieve that I decided to create a plugin and subscribe to the “Operation completed” event:

```
     
using System;
using Serilog;
using Sitecore.Framework.Messaging;
using Sitecore.XConnect.Operations;
using Sitecore.XConnect.Service.Plugins;
using Sitecore.XConnect.ServicePlugins.ContactTracker.Models;

namespace Sitecore.XConnect.ServicePlugins.ContactTracker.Plugins
{
    public class ContactCreationTrackerPlugin : IXConnectServicePlugin, IDisposable
    {
        private XdbContextConfiguration _config;
        private readonly IMessageBus _messageBus;

        public ContactCreationTrackerPlugin(IMessageBus messageBus)
        {
            _messageBus = messageBus;
            Log.Information("Create {0}", nameof(ContactCreationTrackerPlugin));
        }

        /// Subscribes to events the current plugin listens to.
        /// 
        ///   A  object that provides access to the configuration settings.
        /// 
        /// 
        ///   Argument  is a null reference.
        /// 
        public void Register(XdbContextConfiguration config)
        {
            Log.Information("Register {0}", nameof(ContactCreationTrackerPlugin));
            _config = config;
            RegisterEvents();
        }

        /// 
        ///   Unsubscribes from events the current plugin listens to.
        /// 
        public void Unregister()
        {
            Log.Information("Unregister {0}", nameof(ContactCreationTrackerPlugin));
            UnregisterEvents();
        }

        private void RegisterEvents()
        {
            //Subscribe OperationCompleted event
            _config.OperationCompleted += OnOperationCompleted;
        }

        private void UnregisterEvents()
        {
            //Unsubscribe OperationCompleted event
            _config.OperationCompleted -= OnOperationCompleted;
        }

        /// 
        /// Handles the event that is generated when an operation completes.
        /// 
        /// The  that generated the event.
        /// A  object that provides information about the event.
        private void OnOperationCompleted(object sender, XdbOperationEventArgs xdbOperationEventArgs)
        {
            //Check if no exceptions are occurred during executing the operation. If it is, it will not guarantee that contact was created.
            if (xdbOperationEventArgs.Operation.Exception != null)
                return;

            //We need to track only the AddContactOperation operation. Trying to cast to a necessary type.
            var operation = xdbOperationEventArgs.Operation as AddContactOperation;

            //Checking if it is the necessary operation and if an operation execution status is "Succeeded"
            if (operation?.Status == XdbOperationStatus.Succeeded && operation.Entity.Id.HasValue)
            {

                //Sending a message with an id of newly created contact. 
                _messageBus.SendAsync(new CreateDynamicsContactMessage
                {
                    ContactId = operation.Entity.Id.Value
                });
            }
        }

        /// 
        ///   Releases managed and unmanaged resources used by the current class instance.
        /// 
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// 
        ///   Releases managed and unmanaged resources used by the current class instance.
        /// 
        /// 
        ///   Indicates whether the current method was called from explicitly or implicitly during finalization.
        /// 
        protected virtual void Dispose(bool disposing)
        {
            if (!disposing)
                return;
            Log.Information("Dispose {0}", nameof(ContactCreationTrackerPlugin));
            _config = null;
        }
    }
}
```

You can download [ContactCreationTrackerPlugin.cs](https://github.com/ampach/Sitecore.XConnect.ServicePlugins/blob/master/Sitecore.XConnect.ServicePlugins.ContactTracker/Plugins/ContactCreationTrackerPlugin.cs "Contact Creation Tracker Plugin ") file on GIT repository. 

After we add a plugin implementation, we will need to register it in configuration:

```
    
 <Sitecore>
    <XConnect>
      <Collection>
        <Services>             	  <Sitecore.XConnect.ServicePlugins.ContactTracker.Plugins.ContactCreationTrackerPlugin>
            <Type>Sitecore.XConnect.ServicePlugins.ContactTracker.Plugins.ContactCreationTrackerPlugin, Sitecore.XConnect.ServicePlugins.ContactTracker</Type>
            <As>Sitecore.XConnect.Service.Plugins.IXConnectServicePlugin, Sitecore.XConnect.Service.Plugins</As>
            <LifeTime>Singleton</LifeTime>
          </Sitecore.XConnect.ServicePlugins.ContactTracker.Plugins.ContactCreationTrackerPlugin>
        </Services>
      </Collection>
    </XConnect>
  </Sitecore>
</Settings>
```

You can download  [sc.Custom.Service.Plugins.xml](https://github.com/ampach/Sitecore.XConnect.ServicePlugins/blob/master/Sitecore.XConnect.ServicePlugins.ContactTracker/App_Data/Config/sitecore/Collection/sc.Custom.Service.Plugins.xml "Custom.Service Plugin") file on GIT repository.

Then we need to copy a .dll file with your plugin to the bin directory of your xConnect instance and the **sc.Custom.Service.Plugins.xml** file to the xConnect\App\_data\Config\sitecore\Collection folder.

And the end of article I would like to provide probably a full list of operations that you can catch in the plugin:

- AddContactIdentifierOperation
- AddContactOperation
- AddDeviceProfileOperation
- AddInteractionOperation
- ClearFacetOperation
- ClearFacetOperation&lt;TFacet&gt;, where TFacet : Sitecore.XConnect.Facet
- CreateContactCursorOperation
- CreateInteractionCursorOperation
- GetEntityOperation&lt;TEntity&gt;
- GetFacetOperation&lt;TFacet&gt;, where TFacet : Sitecore.XConnect.Facet
- MergeContactsOperation
- PatchFacetOperation&lt;TFacet&gt;, where TFacet : Sitecore.XConnect.Facet
- ReadEntityCursorOperation&lt;TEntity&gt;
- RemoveContactIdentifierOperation
- RightToBeForgottenOperation
- SetFacetOperation
- SetFacetOperation&lt;TFacet&gt;, where TFacet : Sitecore.XConnect.Facet
- SplitEntityCursorOperation
- UpdateDeviceProfileOperation
- XdbSearchOperation&lt;TEntity&gt;

This is a short example of how to implement a service plugin for Sitecore xConnect. Let me know if this was helpful! 

##### 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

[!\[artsiom-photo\](https://www.brimit.com/-/jssmedia/feature/blogs/authors/artsiom-200.jpg?h=202&amp;iar=0&amp;w=200&amp;hash=41797D2540DF6EB6FDF558360F6F62B8)
Artsem Prashkovich
Sitecore MVP/ Solution Architect](https://www.brimit.com/blog/author?authors=Artsem%20Prashkovich)

#### 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=0b4d150d-40b7-425d-8214-d3456ff46d52&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%20xConnect%20How%20To%3A%20Service%20Plugin%20Implementation&amp;kw=Sitecore,%20xConnect,%20Service,%20plugin,%20implement,%20how%20to,%20batch%20&amp;p=https%3A%2F%2Fwww.brimit.com%2Fblog%2Fsitecore-xconnect-service-plugin-implementation&amp;r=&amp;lt=285&amp;evt=pageLoad&amp;sv=2&amp;asc=D&amp;cdb=AQAY&amp;rn=809739)