May 14, 2020

Understanding SharePoint Remote Event Receivers Underlying Architecture

194 Views
Understanding SharePoint Remote Event Receivers Underlying Architecture

Microsoft’s philosophy today is cloud-first with Office 365. With this, it poses a few challenges when it comes to the handling of events in SharePoint Online. In the earlier days of SharePoint, you would write an Event Receiver using Visual Studio and make it available as a Farm Solution. In today’s online environment, this kind of event handlers are called “Remote Event Receivers. Consequently, one needs to use a different set of tools, platforms, and registration process to build these handlers. There are a lot of references available on how to build an RER that one can be readily used. In this post, we would focus on the underlying architecture involved in the registration and the actual execution of the SharePoint Online Events using the Remote Event Receiver (RER) option. Hopefully, that will provide some help during your RER journey.

In this article, I am trying to diagnose the underlying architecture involved in the registration and the actual execution of the SharePoint Online Events using the Remote Event Receiver (RER) option.

Microsoft provided the tooling which is required to register the SharePoint events from the web service using the Provider hosted add-in model. Here is the pictorial depiction of the RER implementation model which leverages the Provider hosted Add-in model.

SharePoint Event Registration:

Understanding SharePoint Remote Event Receivers Underlying Architecture

SharePoint Event Execution

Understanding SharePoint Remote Event Receivers Underlying Architecture

High level RER implementation process

Basically, there are two steps in the whole process of RER implementation and execution.

Registration of the SharePoint Events:
  • As you can notice from the picture, the provider hosted add-in’s run from the externally hosted web application and this web application will have a special web service file, example RER.svc.
  • The web application service will have two methods ProcessWayOut() and ProcessOneWayOut()
  • when the web service is triggered. These methods will validate the incoming EventType and then executes the corresponding events-based activities.
  • For the 1st time when the Add-In is installed the web service will catch the AppInstalled event. Using this Event, the SharePoint List and Item related events are registered.
  • The List and ListItem Events thus registered from the step above will have a same webservice as an endpoint URL.
Event execution
  • Now, when the List or ListItem events are triggered the webservice again validates incoming EventType and it executes corresponding code based on the incoming event.

It is important to notice here that, though the whole process itself may appear complicated, it simply performs few simple activities mentioned below.

  • 1. Register the Events
  • 2. Associate with the Endpoint URL such as WCF service with the registered event receivers
  • 3. Actual execution of the events.

The event registration itself can be done directly by using PowerShell script or through CSOM script as shown pictorially below.

Understanding SharePoint Remote Event Receivers Underlying Architecture

Here is the simple PNP PowerShell script used to register the Event Receiver.


$cred = Get-Credential
Connect-PnPOnline -Url "https://mysite.sharepoint.com/sites/dev" -Credentials $cred
Add-PnPEventReceiver -List "TestList" -Name "ReceiverName" -Url https://customsite.azurewebsites.net/eventreceiver.svc -EventReceiverType ItemAdded -Synchronization Asynchronous 

In the example above, we are trying to associate the event to the list <TestList>.

After executing this code, the list <TestList> will have the event receiver of type ItemAded associated with it.

Here is how you can register the Event using the CSOM Code in C#.


Ensure to include both the references mentioned below.
using Microsoft.SharePoint.Client;
using OfficeDevPnP.Core;

Then use the below code to register the Remote Event Receiver.

Understanding SharePoint Remote Event Receivers Underlying Architecture

In the example above, we are trying to associate the event to all the lists within the site with BaseTemplate of 101. After executing this code, All the document libraries within the site will have the event receiver of type ItemAded associated with them.

As you can notice, there is a receiver URL mentioned here in both the examples above, and this receiver URL need not always be pointing to a webservice.

In the section below let us try to understand the HTTP post data which is sent to the receiver URL and how it can be parsed.

Understanding the HTTP Data Sent to the URL After the Event Occurs

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <ProcessOneWayEvent xmlns="http://schemas.microsoft.com/sharepoint/remoteapp/">
            <properties xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                <AppEventProperties i:nil="true" />
                <ContextToken> kxrQ19oTzBkdkFYMFhja0M0ay1tdkFRV0VlVVYwaDRnQ2hRYmJUQTBydXQ5NDVieFVmeDVGWjV0dWNJcFZtX0traVJDdGlaOTFfTDg4V2Z2TzFINkprTzRPMmhYNTNPckZQRFpOblF1WXFrbVdpRFVTTHI3My11UUJYQVNBQSJ9.98WVAf6WOKbNJmY0w0_O31V-InCGQzuPPNqOYJtwk_8</ContextToken>
                <CorrelationId>42023c9f-a065-0000-4457-fcb2e01c72d0</CorrelationId>
                <CultureLCID>1033</CultureLCID>
                <EntityInstanceEventProperties i:nil="true" />
                <ErrorCode />
                <ErrorMessage />
                <EventType>ItemAdded</EventType>
                <ItemEventProperties>
                    <AfterProperties xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
                        <a:KeyValueOfstringanyType>
                            <a:Key>vti_filesize</a:Key>
                            <a:Value i:type="b:int" 
                                xmlns:b="http://www.w3.org/2001/XMLSchema">0</a:Value>
                        </a:KeyValueOfstringanyType>
                        <a:KeyValueOfstringanyType>
                            <a:Key>vti_previewinvalidtime</a:Key>
                            <a:Value i:type="b:dateTime" 
                                xmlns:b="http://www.w3.org/2001/XMLSchema">2020-03-06T03:50:30</a:Value>
                        </a:KeyValueOfstringanyType>
                        <a:KeyValueOfstringanyType>
                            <a:Key>vti_author</a:Key>
                            <a:Value i:type="b:string" 
                                xmlns:b="http://www.w3.org/2001/XMLSchema">i:0#.f|membership|rajashekharsheelvant@mytenant.onmicrosoft.com</a:Value>
                        </a:KeyValueOfstringanyType>
                        <a:KeyValueOfstringanyType>
                            <a:Key>vti_principalcount</a:Key>
                            <a:Value i:type="b:int" 
                                xmlns:b="http://www.w3.org/2001/XMLSchema">3</a:Value>
                        </a:KeyValueOfstringanyType>
                        <a:KeyValueOfstringanyType>
                            <a:Key>ContentTypeId</a:Key>
                            <a:Value i:type="b:string" 
                                xmlns:b="http://www.w3.org/2001/XMLSchema">0x010100064726A840CD75489C4AC72CB3CB3275</a:Value>
                        </a:KeyValueOfstringanyType>
                        <a:KeyValueOfstringanyType>
                            <a:Key>vti_modifiedby</a:Key>
                            <a:Value i:type="b:string" 
                                xmlns:b="http://www.w3.org/2001/XMLSchema">i:0#.f|membership|rajashekharsheelvant@mytenant.onmicrosoft.com</a:Value>
                        </a:KeyValueOfstringanyType>
                        <a:KeyValueOfstringanyType>
                            <a:Key>vti_sprocsschemaversion</a:Key>
                            <a:Value i:type="b:string" 
                                xmlns:b="http://www.w3.org/2001/XMLSchema">16.0.475.0</a:Value>
                        </a:KeyValueOfstringanyType>
                        <a:KeyValueOfstringanyType>
                            <a:Key>vti_parserversion</a:Key>
                            <a:Value i:type="b:string" 
                                xmlns:b="http://www.w3.org/2001/XMLSchema">16.0.0.19819</a:Value>
                        </a:KeyValueOfstringanyType>
                        <a:KeyValueOfstringanyType>
                            <a:Key>vti_dbschemaversion</a:Key>
                            <a:Value i:type="b:string" 
                                xmlns:b="http://www.w3.org/2001/XMLSchema">16.0.212.0</a:Value>
                        </a:KeyValueOfstringanyType>
                        <a:KeyValueOfstringanyType>
                            <a:Key>vti_writevalidationtoken</a:Key>
                            <a:Value i:type="b:string" 
                                xmlns:b="http://www.w3.org/2001/XMLSchema"> </a:Value>
                        </a:KeyValueOfstringanyType>
                    </AfterProperties>
                    <AfterUrl>Shared Documents/Subfolder1/Subfolder11/Subfolder111/Book1.xlsx</AfterUrl>
                    <BeforeProperties xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
                    <BeforeUrl i:nil="true" />
                    <CurrentUserId>6</CurrentUserId>
                    <ExternalNotificationMessage i:nil="true" />
                    <IsBackgroundSave>false</IsBackgroundSave>
                    <ListId>57791af2-6df7-4d69-981f-10fec61f85a3</ListId>
                    <ListItemId>18</ListItemId>
                    <ListTitle>Documents</ListTitle>
                    <UserDisplayName>Rajashekhar Sheelvant</UserDisplayName>
                    <UserLoginName>i:0#.f|membership|rajshekharsheelvant@mytenant.onmicrosoft.com</UserLoginName>
                    <Versionless>false</Versionless>
                    <WebUrl>https:// mytenant.sharepoint.com/sites/devsite</WebUrl>
                </ItemEventProperties>
                <ListEventProperties i:nil="true" />
                <SecurityEventProperties i:nil="true" />
                <UICultureLCID>1033</UICultureLCID>
                <WebEventProperties i:nil="true" />
            </properties>
        </ProcessOneWayEvent>
    </s:Body>
</s:Envelope>

Every event will send the relevant information related to the event through HTTP post data.

Mentioned below are the important node values you can leverage to perform relevant actions in this HTTP post data above.

The node <EventType>*: Every SharePoint event will have this node, and this will let us know which type of event has occurred.

The node <ContextToken>*: gives the Context Token which can be directly used to get into the context of the list item.

Other important nodes to be noted are.

<WebUrl>, <AfterUrl>, <ListItemId>, <UserLoginName> etc. You can use any one of these node values or any other node values as per your need to perform required action within your code.

You can use any coding language of your choice and should parse the incoming http post data and perform the function as per your requirement.

Below code is a C# example, which converts the incoming HTTPPost to xml doc and reads the node


Str incomingHTTPData = <HTTPPostData> //use relevant method to convert to string as per your environment.

XmlDocument eventData = new XmlDocument();
eventData.LoadXml(incomingHTTPData);

string eventType = eventData.GetElementsByTagName("EventType")[0].InnerXml;

As mentioned initially. The major intention about this article is to unclutter few concepts related to Remote Event Receivers so that it helps you in developing a great solutions leveraging the great power of technology such as Remote event receivers.

Your comments, Queries are most welcome.

Leave a Reply

Your email address will not be published. Required fields are marked *