public void UpdateProvisioningJob(Guid jobId, ProvisioningJobStatus status, String errorMessage = null)
        {
            // Connect to the Infrastructural Site Collection
            using (var context = PnPPartnerPackContextProvider.GetAppOnlyClientContext(PnPPartnerPackSettings.InfrastructureSiteUrl))
            {
                // Get a reference to the target library
                Web  web  = context.Web;
                List list = web.Lists.GetByTitle(PnPPartnerPackConstants.PnPProvisioningJobs);
                context.Load(list, l => l.RootFolder);

                CamlQuery query = new CamlQuery();
                query.ViewXml =
                    @"<View>
                        <Query>
                            <Where>
                                <Eq>
                                    <FieldRef Name='FileLeafRef' />
                                    <Value Type='Text'>" + jobId + @".job</Value>
                                </Eq>
                            </Where>
                        </Query>
                    </View>";

                ListItemCollection items = list.GetItems(query);
                context.Load(items,
                             includes => includes.IncludeWithDefaultProperties(
                                 j => j[PnPPartnerPackConstants.PnPProvisioningJobStatus],
                                 j => j[PnPPartnerPackConstants.PnPProvisioningJobError],
                                 j => j[PnPPartnerPackConstants.PnPProvisioningJobType]),
                             includes => includes.Include(j => j.File));
                context.ExecuteQueryRetry();

                if (items.Count > 0)
                {
                    ListItem jobItem = items[0];

                    // Update the ProvisioningJob object internal status
                    ProvisioningJob job = GetProvisioningJobStreamFromSharePoint(context, jobItem)
                                          .FromJsonStream((String)jobItem[PnPPartnerPackConstants.PnPProvisioningJobType]);

                    job.Status       = status;
                    job.ErrorMessage = errorMessage;

                    // Update the SharePoint ListItem behind the Provisioning Job item
                    // jobItem[PnPPartnerPackConstants.ContentTypeIdField] = PnPPartnerPackConstants.PnPProvisioningJobContentTypeId;
                    jobItem[PnPPartnerPackConstants.PnPProvisioningJobStatus] = status.ToString();
                    jobItem[PnPPartnerPackConstants.PnPProvisioningJobError]  = errorMessage;

                    jobItem.Update();
                    context.ExecuteQueryRetry();

                    // Update the file
                    list.RootFolder.UploadFile(jobItem.File.Name, job.ToJsonStream(), true);
                }
            }
        }
        public Guid EnqueueProvisioningJob(ProvisioningJob job)
        {
            // Prepare the Job ID
            Guid jobId = Guid.NewGuid();

            // Connect to the Infrastructural Site Collection
            using (var context = PnPPartnerPackContextProvider.GetAppOnlyClientContext(PnPPartnerPackSettings.InfrastructureSiteUrl))
            {
                // Set the initial status of the Job
                job.JobId  = jobId;
                job.Status = ProvisioningJobStatus.Pending;

                // Convert the current Provisioning Job into a Stream
                Stream stream = job.ToJsonStream();

                // Get a reference to the target library
                Web  web  = context.Web;
                List list = web.Lists.GetByTitle(PnPPartnerPackConstants.PnPProvisioningJobs);
                Microsoft.SharePoint.Client.File file = list.RootFolder.UploadFile(String.Format("{0}.job", jobId), stream, false);

                Microsoft.SharePoint.Client.User ownerUser = web.EnsureUser(job.Owner);
                context.Load(ownerUser);
                context.ExecuteQueryRetry();

                ListItem item = file.ListItemAllFields;

                item[PnPPartnerPackConstants.ContentTypeIdField]       = PnPPartnerPackConstants.PnPProvisioningJobContentTypeId;
                item[PnPPartnerPackConstants.TitleField]               = job.Title;
                item[PnPPartnerPackConstants.PnPProvisioningJobStatus] = ProvisioningJobStatus.Pending.ToString();
                item[PnPPartnerPackConstants.PnPProvisioningJobError]  = String.Empty;
                item[PnPPartnerPackConstants.PnPProvisioningJobType]   = job.GetType().FullName;

                FieldUserValue ownerUserValue = new FieldUserValue();
                ownerUserValue.LookupId = ownerUser.Id;
                item[PnPPartnerPackConstants.PnPProvisioningJobOwner] = ownerUserValue;

                item.Update();

                context.ExecuteQueryRetry();

                // Check if we need to enqueue a message in the Azure Storage Queue, as well
                // This happens when the Provisioning Job has to be executed in Continous mode
                if (PnPPartnerPackSettings.ContinousJobHandlers.ContainsKey(job.GetType()))
                {
                    // Get the storage account for Azure Storage Queue
                    CloudStorageAccount storageAccount =
                        CloudStorageAccount.Parse(PnPPartnerPackSettings.StorageQueueConnectionString);

                    // Get queue ... and create if it does not exist
                    CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();
                    CloudQueue       queue       = queueClient.GetQueueReference(PnPPartnerPackSettings.StorageQueueName);
                    queue.CreateIfNotExists();

                    // Add entry to queue
                    ContinousJobItem content = new ContinousJobItem {
                        JobId = job.JobId
                    };
                    queue.AddMessage(new CloudQueueMessage(JsonConvert.SerializeObject(content)));
                }
            }

            return(jobId);
        }