We were recently working on automating back-end processes on SharePoint for a client, and had chosen
SharePoint PnP Timer Job Framework as our base SDK to build our background processes to enable them to execute against all versions of SharePoint, including online and on-prem.
We initially developed against SharePoint Online and everything worked smoothly. Our
TimerJob derived jobs worked just fine and applied our logic correctly against Office 365 SharePoint. However, when our we tested the same Jobs against in-house SharePoint test environments, we observed unexpected
NullReferenceExceptions in our
TimerJob.TimerJobRun event handlers. On debugging, we noticed all the
ClientContext instances (namely
TimerJobRunEventArgs.WebClientContext) were coming across as null in
As we debugged into reasons for the same, no noticeable red flag cropped up and all our code was written as it should for a
TimerJob. We tried with bare skeleton TimeJobs against the in-house SharePoint test environments, and they produced the same errors,
ClientContext instances were null in
Then we noticed the
SharePointVersion property on the
TimerJob instance. Its description says:
Gets or sets the SharePoint version. Default value is detected based on the laoded CSOM assembly version,
but can be overriden in case you want to for example use v16 assemblies in v15 (on-premises)
Well we were executing against SharePoint 2013, and with NuGet packages being the de-facto standard for referencing SDKs, we certainly were on the latest versions of SharePointPnPCoreOnline and Microsoft.SharePointOnline.CSOM nuget packages. The CSOM package version we were using was 16.1.7115.1200, which meant we were essentially using CSOM version 16 with SharePoint version 15.
The below table summaries various SharePoint public and internal version numbers:
|Public Version||Internal Version|
|SharePoint Online||16 (as of writing this)|
The SharePoint Online / Office 365 version is usually the latest stable SharePoint version, and can change with newer SharePoint releases.
Anyways coming back, all we needed to fix the Object reference errors was to set
SharePointVersion to 15 explicitly in code, and that again started producing the
ClientContext instances correctly in
TimerJobRun handler. We figured it was probably a good idea to always explicitly specify
TimerJob instances to make the code future proof as nuget packages can be upgraded anytime. Additionally in our case, because the destination SharePoint site urls were being picked dynamically at run-time from configuration, we added an additional property to specify the SharePoint version for those urls in the configuration itself. You can choose to either hard-code or use another appropriate mechanism to figure out the correct SharePoint version to set on your job instances.