Webhook Success Key #2: Track SharePoint Change History

John E. Huschka, January 25, 2018

Target Audience:
SharePoint Developer
Technology:

Azure Functions — Internet cloud based custom code for SharePoint and Office 365.

SharePoint Webhooks — Connections that allow us to attach custom code to SharePoint that is called when events occur.

This post is part of our blog series and demonstration code on achieving webhook success.

You might assume that SharePoint webhooks are like other event architectures (such as database triggers) where a SharePoint event immediately triggers a webhook, like this:

 
Event in SharePoint
Webhook triggered. Azure function called.
Event in SharePoint
Webhook triggered. Azure function called.
Event in SharePoint
Webhook triggered. Azure function called.
Event in SharePoint
Webhook triggered. Azure function called.
Event in SharePoint
Webhook triggered. Azure function called.
 

This is not how SharePoint webhooks work. With SharePoint webhooks, multiple SharePoint events happen and then the webhook is called approximately once per minute:

 
0:00:00
Event in SharePoint
 
0:00:12
Event in SharePoint
 
0:00:25
Event in SharePoint
 
0:00:47
Event in SharePoint
 
0:00:53
Event in SharePoint
 
0:01:00
 
Webhook triggered. Azure function called.
 

The webhook request content sent to your handler will appear similar to the following

 
{
	"value": [{
	"subscriptionId": "b95bbc51-1fe3-4428-b2bc-1af28de60d94",
	"clientState": "CFWebHookDemo",
	"expirationDateTime": "2018-02-04T21:54:46.4940000Z",
	"resource": "038a9b03-4c33-4b2e-aadf-070a724d6337",
	"tenantId": "2b375469-c5ab-424e-9358-232b0848726b",
	"siteUrl": "/sites/WebhookDemo",
	"webId": "ab08cd87-f4c3-497b-b4f9-01f12b241954"
	}]
}
 

Note that it doesn’t provide details regarding the changes that have occurred. It has provided the SharePoint context (siteUrl, webId, and the resource, such as a list, to which your webhook is attached). It is now up to you to query the SharePoint change log to find out what events have occurred.

Specifically, in our example, the QueueTransactionProcessor submits a ChangeQuery back to SharePoint asking for event details.

The ChangeQuery includes a token (a semi-colon delimited String) that defines the SharePoint events for which it is requesting details. Here is a sample of how the token will appear:

 
1;3;038a9b03-4c33-4b2e-aadf-070a724d6337;636511279111300000;101894028
 

The token is defined this way:

Version
Scope
Scope Id
Event Time
Change Number
Currently always "1"
0 = content database
1 = site collection
2 = site
3 = list
The Id of the SharePoint object for which events are to be returned.
Time, in ticks, beginning at which SharePoint is to return events.
Supply "-1" to get all changes. We track the previous token, so we have the previous change number.

Notice this: Every value in our token except the event time is a known constant for a specific webhook. If we are going to avoid re-querying and re-processing events that we already have processed, we must know the time for which we last processed events.

In other words, our challenge is the following:

 
0:00:00
Start
 
Bunch of events in SharePoint
0:01:00
Webhook is triggered. Azure function called. Our function queries and processes those events.
 
Bunch of events in SharePoint
0:02:00
Webhook is triggered. Azure function called. Our function must know that it already queried and processed events at the 1:00 mark, so that it can retrieve events between 1:00 and 2:00.
 

This is why our solution maintains a Webhook History list in SharePoint:

Webhook History List

Our QueueTransactionProcessor, which is responsible for querying and processing the SharePoint changes, saves the latest SharePoint change token that it receives in this list:

Then, when the next webhook call is received, it retrieves this token from the Webhook History list to construct a new change token for querying the next set of changes:

In Microsoft's SharePoint Web Hooks reference implementation, this state persistence is provided by an Azure database within the ChangeManager. We have chosen to use SharePoint rather than introduce an additional datastore.


 


We at Collaboration Foundry are experts in SharePoint and Office 365. If you need assistance, we can help. Contact us.
Also, don't forget to take a look at our blog for more helpful tips and techniques.


Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
CAPTCHAThis question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
1 + 6 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.