PnP-Zeitgeberauftrag-Framework
Beim PnP-Zeitgeberauftrag-Framework handelt es sich um eine Reihe von Klassen, die die Erstellung von Hintergrundprozessen vereinfachen sollen, die für SharePoint-Websites ausgeführt werden. Das Zeitgeberauftragsframework ähnelt lokalen voll vertrauenswürdigen Codetimeraufträgen (SPJobDefinition). Der Hauptunterschied zwischen dem Zeitgeberauftragsframework und dem voll vertrauenswürdigen Codetimerauftrag besteht darin, dass das Zeitgeberauftragsframework nur clientseitige APIs verwendet und daher außerhalb von SharePoint ausgeführt werden kann (und sollte). Das Zeitgeberauftragsframework ermöglicht das Erstellen von Zeitgeberaufträgen, die für SharePoint Online ausgeführt werden.
Nachdem ein Zeitgeberauftrag erstellt wurde, muss er geplant und ausgeführt werden. Die beiden häufigsten Optionen sind:
- Wenn Microsoft Azure die Hostingplattform ist, können Zeitgeberaufträge als Azure-WebJobs bereitgestellt und ausgeführt werden.
- Wenn Windows Server die Hostingplattform ist (z. B. für lokale SharePoint), können Zeitgeberaufträge in Windows Scheduler bereitgestellt und ausgeführt werden.
Eine Video-Einführung in Zeitgeberaufträge finden Sie im Video Einführung in das PnP-Zeitgeberauftragsframework, das das Zeitgeberauftragsframework vorstellt und das Einfache Zeitgeberauftragsbeispiel veranschaulicht.
Beispiel für einfachen Zeitgeberauftrag
In diesem Abschnitt erfahren Sie, wie Sie einen sehr einfachen Zeitgeberauftrag erstellen. Das Ziel dieses Beispiels besteht darin, dem Leser einen schnellen Überblick zu bieten. Später bieten wir eine ausführlichere Erläuterung des Zeitgeberauftragsframeworks.
Hinweis
Eine umfangreichere PnP-Lösung mit zehn einzelnen Beispielen für Zeitgeberaufträge, von "Hello World"-Beispielen bis hin zu tatsächlichen Inhaltsablaufaufträgen, finden Sie unter Core.TimerJobs.Samples.
In den folgenden Schritten wird beschrieben, wie Sie einen einfachen Zeitgeberauftrag erstellen.
Schritt 1: Erstellen eines Konsolenprojekts und Verweisen auf PnP Core
Erstellen Sie ein neues Projekt vom Typ "console", und verweisen Sie auf die PnP Core-Bibliothek, indem Sie eine der folgenden Aktionen ausführen:
Fügen Sie ihrem Projekt das NuGet-Paket Office 365 Developer Patterns and Practices Core hinzu. Es gibt ein NuGet-Paket für v15 (lokal) und für v16 (Office 365). Dies ist die bevorzugte Option.
Fügen Sie ihrem Projekt das vorhandene PnP Core-Quellprojekt hinzu. Auf diese Weise können Sie beim Debuggen den PnP-Kerncode schrittweise ausführen.
Hinweis
Sie sind dafür verantwortlich, diesen Code mit den neuesten Änderungen zu aktualisieren, die PnP hinzugefügt wurden.
Schritt 2: Erstellen einer Zeitgeberauftragsklasse und Hinzufügen ihrer Zeitgeberauftragslogik
Fügen Sie eine Klasse für den Zeitgeberauftrag mit dem Namen SimpleJob hinzu.
Lassen Sie die Klasse die abstrakte TimerJob-Basisklasse erben.
Geben Sie im Konstruktor dem Zeitgeberauftrag einen Namen (
base("SimpleJob")
), und verbinden Sie den TimerJobRun-Ereignishandler .Fügen Sie dem TimerJobRun-Ereignishandler Ihre Zeitgeberauftragslogik hinzu.
Das Ergebnis sieht in etwa wie folgt aus:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.SharePoint.Client;
using OfficeDevPnP.Core.Framework.TimerJobs;
namespace Core.TimerJobs.Samples.SimpleJob
{
public class SimpleJob: TimerJob
{
public SimpleJob() : base("SimpleJob")
{
TimerJobRun += SimpleJob_TimerJobRun;
}
void SimpleJob_TimerJobRun(object sender, TimerJobRunEventArgs e)
{
e.WebClientContext.Load(e.WebClientContext.Web, p => p.Title);
e.WebClientContext.ExecuteQueryRetry();
Console.WriteLine("Site {0} has title {1}", e.Url, e.WebClientContext.Web.Title);
}
}
}
Schritt 3: Aktualisieren von Program.cs für die Verwendung des Zeitgeberauftrags
Der im vorherigen Schritt erstellte Zeitgeberauftrag muss weiterhin ausgeführt werden. Aktualisieren Sie hierzu Program.cs mithilfe der folgenden Schritte:
Instanziieren Sie Ihre Zeitgeberauftragsklasse.
Geben Sie die Authentifizierungsdetails für den Zeitgeberauftrag an. In diesem Beispiel werden der Benutzername und das Kennwort für die Authentifizierung bei SharePoint Online verwendet.
Fügen Sie eine oder mehrere Websites hinzu, auf die das Zeitgeberauftragsprogramm zugreifen kann. In diesem Beispiel wird ein wilder Karte Zeichen in der URL verwendet. Der Zeitgeberauftrag wird auf allen Websites ausgeführt, die diesem wilden Karte-URL entsprechen.
Starten Sie den Zeitgeberauftrag, indem Sie die Run-Methode aufrufen.
static void Main(string[] args)
{
// Instantiate the timer job class
SimpleJob simpleJob = new SimpleJob();
// The provided credentials need access to the site collections you want to use
simpleJob.UseOffice365Authentication("user@tenant.onmicrosoft.com", "pwd");
// Add one or more sites to operate on
simpleJob.AddSite("https://<tenant>.sharepoint.com/sites/d*");
// Run the job
simpleJob.Run();
}
Bereitstellungsoptionen für Zeitgeberaufträge
Im vorherigen Schritt wird ein einfacher Zeitgeberauftrag veranschaulicht. Der nächste Schritt besteht darin, den Zeitgeberauftrag bereitzustellen.
Ein Zeitgeberauftrag ist eine .exe-Datei, die auf einer Hostingplattform geplant werden muss. Je nach ausgewählter Hostingplattform unterscheidet sich die Bereitstellung. In den folgenden Abschnitten werden die beiden häufigsten Hostingplattformoptionen beschrieben:
- Verwenden von Azure als Hostingplattform.
- Verwenden von Windows Server als Hostingplattform.
Bereitstellen von Zeitgeberaufträgen in Azure mithilfe von Azure WebJobs
Stellen Sie vor dem Bereitstellen eines Zeitgeberauftrags sicher, dass der Auftrag ohne Benutzerinteraktion ausgeführt werden kann. Im Beispiel in diesem Artikel wird der Benutzer aufgefordert, ein Kennwort oder einen geheimen Clientschlüssel anzugeben (weitere Informationen finden Sie im Abschnitt Authentifizierung ). Dies funktioniert beim Testen, funktioniert aber bei der Bereitstellung nicht. Alle vorhandenen Beispiele ermöglichen es dem Benutzer, mithilfe der app.config-Datei ein Kennwort oder einen geheimen Clientschlüssel anzugeben:
<appSettings>
<add key="user" value="user@tenant.onmicrosoft.com"/>
<add key="password" value="your password goes here!"/>
<add key="domain" value="Contoso"/>
<add key="clientid" value="a4cdf20c-3385-4664-8302-5eab57ee6f14"/>
<add key="clientsecret" value="your clientsecret goes here!"/>
</appSettings>
Nachdem diese Änderungen der app.config-Datei hinzugefügt wurden, führen Sie den Zeitgeberauftrag aus Visual Studio aus, um zu bestätigen, dass er ohne Benutzerinteraktion ausgeführt wird.
Die tatsächliche Bereitstellung in Azure basiert auf Azure WebJobs. Führen Sie die folgenden Schritte aus, um dieses Beispiel für einen Zeitgeberauftrag bereitzustellen:
Klicken Sie in Visual Studio mit der rechten Maustaste auf das Projekt, und wählen Sie Als Azure-Webjob veröffentlichen aus.
Geben Sie einen Zeitplan für den Zeitgeberauftrag an, und wählen Sie dann OK aus.
Wählen Sie Microsoft Azure-Websites als Veröffentlichungsziel aus. Sie werden aufgefordert, sich bei Azure anzumelden und die Azure-Website auszuwählen, auf der der Zeitgeberauftrag gehostet wird (Sie können auch einen neuen erstellen, wenn dies erforderlich wäre).
Wählen Sie Veröffentlichen aus, um den WebJob per Push an Azure zu übertragen.
Nachdem der Zeitgeberauftrag veröffentlicht wurde, können Sie den Auftrag auslösen und die Auftragsausführung in Visual Studio oder im Azure-Portal überprüfen.
Außerdem kann der Zeitgeberauftrag über die neue Azure-Portal ausgeführt werden, indem Sie den Auftrag auswählen und Ausführen auswählen. Weitere Informationen zum Arbeiten mit WebJobs über das neue Portal finden Sie im Artikel Ausführen von Hintergrundaufgaben mit WebJobs in Azure App Service.
Hinweis
Ausführliche Anleitungen zum Bereitstellen eines Azure-WebJobs finden Sie unter Erste Schritte mit Azure WebJobs (Zeitgeberaufträge) für Ihre Office 365-Websites.
Bereitstellen von Zeitgeberaufträgen für Windows Server mithilfe des Windows-Schedulers
Bei der Bereitstellung auf Windows Server muss der Zeitgeberauftrag ohne Benutzerinteraktion ausgeführt werden.
Ändern Sie die app.config-Datei wie im vorherigen Abschnitt Bereitstellen von Zeitgeberaufträgen in Azure mithilfe von Azure WebJobs beschrieben.
Kopieren Sie die Releaseversion Ihres Auftrags auf den Server, auf dem er ausgeführt werden soll.
Wichtig
Kopieren Sie alle relevanten Assemblys, die .exe-Datei und die .config-Datei, um sicherzustellen, dass der Auftrag auf dem Server ausgeführt werden kann, ohne zusätzliche Dateien oder Programme auf dem Server zu installieren.
Planen Sie die Ausführung des Zeitgeberauftrags. Es wird empfohlen, den integrierten Windows-Aufgabenplaner zu verwenden. So verwenden Sie die Windows-Aufgabenplanung:
- Öffnen Sie den Taskplaner (Systemsteuerung>Task Scheduler).
- Wählen Sie Aufgabe erstellen aus, und geben Sie einen Namen und ein Konto an, das die Aufgabe ausführt.
- Wählen Sie Trigger aus , und fügen Sie einen neuen Trigger hinzu. Geben Sie den gewünschten Zeitplan für den Zeitgeberauftrag an.
- Wählen Sie Aktionen und dann die Aktion Programm starten aus, wählen Sie den Zeitgeberauftrag .exe Datei aus, und legen Sie dann den Start im Ordner fest.
- Wählen Sie OK aus, um die Aufgabe zu speichern.
Zeitgeberauftragsframework im Detail
In diesem Abschnitt werden die Features des Zeitgeberauftragsframeworks und deren Funktionsweise erläutert.
Structure
Die TimerJob-Klasse ist eine abstrakte Basisklasse, die die folgenden öffentlichen Eigenschaften, Methoden und Ereignisse enthält:
Die meisten Eigenschaften und Methoden werden in den kommenden Abschnitten ausführlicher erläutert. Die restlichen Eigenschaften und Methoden werden hier beschrieben:
- IsRunning-Eigenschaft : Ruft einen Wert ab, der angibt, ob der Zeitgeberauftrag ausgeführt wird. Der Wert true , wenn ausgeführt wird; false , wenn nicht ausgeführt wird.
- Name-Eigenschaft : Ruft den Namen des Zeitgeberauftrags ab. Der Name wird anfänglich im Zeitgeberauftragskonstruktor festgelegt.
- SharePointVersion-Eigenschaft : Ruft die SharePoint-Version ab oder legt sie fest. Diese Eigenschaft wird automatisch basierend auf der Version des geladenen Microsoft.SharePoint.Client.dll festgelegt und sollte sich im Allgemeinen nicht ändern. Sie können diese Eigenschaft jedoch ändern, falls Sie die v16-CSOM-Bibliotheken in einer (lokalen) v15-Bereitstellung verwenden möchten.
- Version-Eigenschaft : Ruft die Version dieses Zeitgeberauftrags ab. Die Version wird anfänglich im Timerauftragskonstruktor oder auf 1.0 festgelegt, wenn sie nicht über den Konstruktor festgelegt wird.
Um sich auf die Ausführung eines Zeitgeberauftrags vorzubereiten, müssen Sie ihn zuerst konfigurieren:
- Geben Sie Authentifizierungseinstellungen an.
- Geben Sie einen Bereich an, bei dem es sich um eine Liste von Websites handelt.
- Legen Sie optional Die Eigenschaften des Zeitgeberauftrags fest.
Aus Sicht der Ausführung werden die folgenden allgemeinen Schritte ausgeführt, wenn eine Zeitgeberauftragsausführung gestartet wird:
- Websites auflösen: UrLs für wild Karte Website (z. B
https://tenant.sharepoint.com/sites/d*
. ) werden in eine tatsächliche Liste vorhandener Websites aufgelöst. Wenn eine Erweiterung der Unterwebsite angefordert wurde, wird die Liste der aufgelösten Websites mit allen Unterwebsites erweitert. - Erstellen Sie Arbeitsbatches basierend auf den aktuellen Tritteinstellungen, und erstellen Sie einen Thread pro Batch.
- Die Threads führen Arbeitsbatches aus und rufen das TimerJobRun-Ereignis für jeden Standort in der Liste auf.
Weitere Details zu den einzelnen Schritten finden Sie in den nächsten Abschnitten.
Authentifizierung
Bevor ein Zeitgeberauftrag verwendet werden kann, muss der Zeitgeberauftrag wissen, wie er sich bei SharePoint authentifiziert. Das Framework unterstützt derzeit die Ansätze in der AuthenticationType-Enumeration : Office365, NetworkCredentials und AppOnly. Mithilfe der folgenden Methoden wird die AuthenticationType-Eigenschaft auch automatisch auf den entsprechenden Wert von Office365, NetworkCredentials und AppOnly festgelegt.
Das folgende Flussdiagramm zeigt die auszuführenden Schritte, gefolgt von detaillierten Erläuterungen zu den einzelnen Ansätzen.
Benutzeranmeldeinformationen
Um Benutzeranmeldeinformationen für die Ausführung für Office 365 anzugeben, können Sie die folgenden beiden Methoden verwenden:
public void UseOffice365Authentication(string userUPN, string password)
public void UseOffice365Authentication(string credentialName)
Die erste Methode akzeptiert einen Benutzernamen und ein Kennwort. Mit der zweiten können Sie generische Anmeldeinformationen angeben, die im Windows-Anmeldeinformations-Manager gespeichert sind. Der folgende Screenshot zeigt die bertonline
generischen Anmeldeinformationen. Um dies zum Authentifizieren des Zeitgeberauftrags zu verwenden, geben Sie bertonline
als Parameter der zweiten Methode an.
Es gibt ähnliche Methoden für die Ausführung für lokale SharePoint-Instanzen:
public void UseNetworkCredentialsAuthentication(string samAccountName, string password, string domain)
public void UseNetworkCredentialsAuthentication(string credentialName)
Nur App
Die reine App-Authentifizierung ist die bevorzugte Methode , da Sie Mandantenberechtigungen erteilen können. Für Benutzeranmeldeinformationen muss das Benutzerkonto über die erforderlichen Berechtigungen verfügen.
Hinweis
Bestimmte Logik zum Auflösen von Websites funktioniert nicht mit der reinen App-Authentifizierung. Details finden Sie im nächsten Abschnitt.
Verwenden Sie eine der folgenden Methoden, um den Auftrag für die reine App-Authentifizierung zu konfigurieren:
public void UseAppOnlyAuthentication(string clientId, string clientSecret)
public void UseAzureADAppOnlyAuthentication(string clientId, string clientSecret)
Dieselbe Methode kann entweder für Office 365 oder lokale SharePoint-Instanzen verwendet werden, wodurch Zeitgeberaufträge, die die reine App-Authentifizierung verwenden, problemlos zwischen Umgebungen übertragen werden können.
Hinweis
Wenn Sie die reine App-Authentifizierung verwenden, schlägt Ihre Zeitgeberauftragslogik fehl, wenn APIs verwendet werden, die nicht mit AuthenticationType.AppOnly funktionieren. Typische Beispiele sind die Such-API, das Schreiben in den Taxonomiespeicher und die Verwendung der Benutzerprofil-API.
Zu betreibende Websites
Wenn ein Zeitgeberauftrag ausgeführt wird, muss mindestens ein Standort ausgeführt werden.
Hinzufügen von Websites zu einem Zeitgeberauftrag
Verwenden Sie die folgenden Methoden, um einem Zeitgeberauftrag Websites hinzuzufügen:
public void AddSite(string site)
public void ClearAddedSites()
Um eine Website hinzuzufügen, geben Sie entweder eine vollqualifizierte URL (z. Bhttps://tenant.sharepoint.com/sites/dev
. ) oder einen wilden Karte-URL an.
Eine wild Karte URL ist eine URL, die mit einem Sternchen (*
) endet. Es ist nur ein Einzelner *
zulässig, und es muss das letzte Zeichen der URL sein. Ein Beispiel für Karte URL, https://tenant.sharepoint.com/sites/*
der alle Websitesammlungen unter dem verwalteten Pfad dieser Website zurückgibt. Ein weiteres Beispiel gibt alle Websitesammlungen zurück, https://tenant.sharepoint.com/sites/dev*
in denen die URL enthält dev
.
In der Regel werden die Websites von dem Programm hinzugefügt, das das Zeitgeberauftragsobjekt instanziiert, aber bei Bedarf kann der Zeitgeberauftrag die Kontrolle über die übergebene Liste der Standorte übernehmen. Fügen Sie hierzu eine Methodenüberschreibung für die UpdateAddedSites
virtuelle Methode hinzu, wie im folgenden Beispiel gezeigt:
public override List<string> UpdateAddedSites(List<string> addedSites)
{
// Let's assume we're not happy with the provided list of sites, so first clear it
addedSites.Clear();
// Manually adding a new wildcard Url, without an added URL the timer job will do...nothing
addedSites.Add("https://bertonline.sharepoint.com/sites/d*");
// Return the updated list of sites
return addedSites;
}
Angeben von Enumerationsanmeldeinformationen
Geben Sie nach dem Hinzufügen einer wilden Karte-URL und dem Festlegen der Authentifizierung auf app-only die Anmeldeinformationen für die Enumeration an. Enumerationsanmeldeinformationen werden verwendet, um eine Liste von Websitesammlungen abzurufen, die im Websiteabgleichsalgorithmus verwendet werden, um eine echte Liste von Websites zurückzugeben.
Zum Abrufen einer Liste von Websitesammlungen verhält sich das Timerframework zwischen Office 365 (v16) und lokal (v15) unterschiedlich:
- Office 365: Die Tenant.GetSiteProperties-Methode wird verwendet, um die "regulären" Websitesammlungen zu lesen. Die Such-API wird verwendet, um die OneDrive for Business Websitesammlungen zu lesen.
- SharePoint lokal: Die Such-API wird verwendet, um alle Websitesammlungen zu lesen.
Da die Such-API nicht mit einem Benutzerkontext funktioniert, greift der Zeitgeberauftrag auf die angegebenen Enumerationsanmeldeinformationen zurück.
Um Benutzeranmeldeinformationen für die Ausführung für Office 365 anzugeben, können Sie die folgenden beiden Methoden verwenden:
public void SetEnumerationCredentials(string userUPN, string password)
public void SetEnumerationCredentials(string credentialName)
Es gibt ähnliche Methoden für die Ausführung für lokale SharePoint-Instanzen:
public void SetEnumerationCredentials(string samAccountName, string password, string domain)
public void SetEnumerationCredentials(string credentialName)
Die erste Methode akzeptiert einfach einen Benutzernamen, ein Kennwort und optional eine Domäne (lokal). Die zweite gibt generische Anmeldeinformationen an, die im Windows-Anmeldeinformations-Manager gespeichert sind. Weitere Informationen zum Anmeldeinformations-Manager finden Sie im Abschnitt Authentifizierung .
Unterwebsite wird erweitert
Häufig möchten Sie, dass der Zeitgeberauftragscode für die Stammwebsite der Websitesammlung und für alle Unterwebsites dieser Websitesammlung ausgeführt wird. Legen Sie dazu die ExpandSubSites-Eigenschaft auf true fest. Dies bewirkt, dass der Zeitgeberauftrag die Unterwebsites im Rahmen des Schritts zum Auflösen des Standorts erweitert.
Überschreiben aufgelöster und/oder erweiterter Websites
Nachdem das Timerframework die wilden Karte Websites aufgelöst und optional die Unterwebsites erweitert hat, besteht der nächste Schritt darin, die Liste der Websites zu verarbeiten. Bevor Sie die Liste der Websites verarbeiten, sollten Sie die Liste der Websites ändern. Beispielsweise können Sie bestimmte Websites entfernen oder der Liste weitere Websites hinzufügen. Dies kann erreicht werden, indem die virtuelle ResolveAddedSites-Methode überschrieben wird. Im folgenden Beispiel wird gezeigt, wie die ResolveAddedSites-Methode außer Kraft gesetzt wird, um eine Website aus der Liste zu entfernen.
public override List<string> ResolveAddedSites(List<string> addedSites)
{
// Use default TimerJob base class site resolving
addedSites = base.ResolveAddedSites(addedSites);
//Delete the first one from the list...simple change. A real life case could be reading the site scope
//from a SQL (Azure) DB to prevent the whole site resolving.
addedSites.RemoveAt(0);
//Return the updated list of resolved sites...this list will be processed by the timer job
return addedSites;
}
TimerJobRun-Ereignis
Das Zeitgeberauftragsframework teilt die Liste der Standorte in Arbeitsbatches auf. Jeder Batch von Websites wird in einem eigenen Thread ausgeführt. Standardmäßig erstellt das Framework fünf Batches und fünf Threads, um diese fünf Batches auszuführen. Weitere Informationen zu Timerauftragsthreadingoptionen finden Sie im Abschnitt Threading .
Wenn ein Thread einen Batch verarbeitet, wird das TimerJobRun-Ereignis vom Timerframework ausgelöst und stellt alle erforderlichen Informationen bereit, um den Timerauftrag auszuführen. Timeraufträge werden als Ereignisse ausgeführt, sodass der Code einen Ereignishandler mit dem TimerJobRun-Ereignis verbinden muss:
public SimpleJob() : base("SimpleJob")
{
TimerJobRun += SimpleJob_TimerJobRun;
}
void SimpleJob_TimerJobRun(object sender, TimerJobRunEventArgs e)
{
// your timer job logic goes here
}
Ein alternativer Ansatz ist die Verwendung eines Inlinedelegaten, wie hier gezeigt:
public SimpleJob() : base("SimpleJob")
{
// Inline delegate
TimerJobRun += delegate(object sender, TimerJobRunEventArgs e)
{
// your timer job logic goes here
};
}
Wenn das TimerJobRun-Ereignis ausgelöst wird, erhalten Sie ein TimerJobRunEventArgs-Objekt , das die erforderlichen Informationen zum Schreiben der Zeitgeberauftragslogik bereitstellt. Die folgenden Attribute und Methoden sind in dieser Klasse verfügbar:
Einige der Eigenschaften und alle Methoden werden in der optionalen Zustandsverwaltungsfunktion verwendet, die im nächsten Abschnitt erläutert wird. Die folgenden Eigenschaften sind jedoch immer in jedem Ereignis verfügbar, unabhängig von der verwendeten Konfiguration:
- URL-Eigenschaft : Ruft die URL der Website ab, für die der Zeitgeberauftrag verwendet werden soll, oder legt diese fest. Dies kann die Stammwebsite der Websitesammlung sein, aber es kann auch eine Unterwebsite sein, falls die Websiteerweiterung durchgeführt wurde.
- ConfigurationData-Eigenschaft : Ruft zusätzliche Zeitgeberauftragskonfigurationsdaten ab oder legt diese fest (optional). Diese Konfigurationsdaten werden als Teil des TimerJobRunEventArgs-Objekts übergeben.
- WebClientContext-Eigenschaft : Ruft das ClientContext-Objekt für die aktuelle URL ab oder legt es fest. Diese Eigenschaft ist ein ClientContext-Objekt für die in der Url-Eigenschaft definierte Website. Dies ist in der Regel das ClientContext-Objekt , das Sie in Ihrem Zeitgeberauftragscode verwenden würden.
- SiteClientContext-Eigenschaft : Ruft das ClientContext-Objekt für die Stammwebsite der Websitesammlung ab oder legt es fest. Diese Eigenschaft bietet Zugriff auf die Stammwebsite, wenn der Zeitgeberauftrag Zugriff darauf erfordert. Beispielsweise kann der Zeitgeberauftrag dem master Seitenkatalog mithilfe der SiteClientContext-Eigenschaft ein Seitenlayout hinzufügen.
- TenantClientContext-Eigenschaft : Ruft das ClientContext-Objekt für die Verwendung mit der Mandanten-API ab oder legt es fest. Diese Eigenschaft stellt ein ClientContext-Objekt bereit, das mithilfe der URL der Mandantenadministratorwebsite erstellt wurde. Um die Mandanten-API im Timerauftrag TimerJobRun-Ereignishandler zu verwenden, erstellen Sie mithilfe dieser TenantClientContext-Eigenschaft ein neues Tenant-Objekt.
Alle ClientContext-Objekte verwenden die im Abschnitt Authentifizierung beschriebenen Authentifizierungsinformationen . Wenn Sie sich für Benutzeranmeldeinformationen entschieden haben, stellen Sie sicher, dass das verwendete Konto über die erforderlichen Berechtigungen verfügt, um für die angegebenen Websites zu arbeiten. Wenn Sie nur app verwenden, empfiehlt es sich, mandantenbezogene Berechtigungen auf den App-Prinzipal festzulegen.
Zustandsverwaltung
Wenn Sie Zeitgeberauftragslogik schreiben, müssen Sie den Zustand häufig beibehalten. Beispielsweise, um aufzuzeichnen, wann ein Standort zuletzt verarbeitet wurde, oder um Daten zur Unterstützung ihrer Zeitgeberauftrags-Geschäftslogik zu speichern. Aus diesem Grund verfügt das Zeitgeberauftragsframework über Zustandsverwaltungsfunktionen.
Die Zustandsverwaltung speichert und ruft einen Satz von Standard- und benutzerdefinierten Eigenschaften als serialisierte JSON-Zeichenfolge im Webeigenschaftenbehälter der verarbeiteten Website ab (Name = Zeitgeberauftragsname + "_Properties"). Im Folgenden sind die Standardeigenschaften des TimerJobRunEventArgs-Objekts aufgeführt:
- PreviousRun-Eigenschaft : Ruft das Datum und die Uhrzeit der vorherigen Ausführung ab oder legt diese fest.
- PreviousRunSuccessful-Eigenschaft : Ruft einen Wert ab, der angibt, ob die vorherige Ausführung erfolgreich war, oder legt einen Wert fest. Beachten Sie, dass der Autor des Zeitgeberauftrags dafür verantwortlich ist, eine Auftragsausführung als erfolgreich zu kennzeichnen, indem er die CurrentRunSuccessful-Eigenschaft als Teil Ihrer Zeitgeberauftragsimplementierung festlegt.
- PreviousRunVersion-Eigenschaft : Ruft die Timerauftragsversion der vorherigen Ausführung ab oder legt diese fest.
Neben diesen Standardeigenschaften haben Sie auch die Möglichkeit, eigene Eigenschaften anzugeben, indem Sie der Properties-Auflistung des TimerJobRunEventArgs-Objekts Schlüsselwort (keyword)-Wert-Paare hinzufügen. Um dies zu vereinfachen, gibt es drei Methoden, die Ihnen helfen:
- SetProperty fügt eine Eigenschaft hinzu oder aktualisiert sie.
- GetProperty gibt den Wert einer Eigenschaft zurück.
- DeleteProperty entfernt eine Eigenschaft aus der Eigenschaftenauflistung.
Der folgende Code zeigt, wie die Zustandsverwaltung verwendet werden kann:
void SiteGovernanceJob_TimerJobRun(object o, TimerJobRunEventArgs e)
{
try
{
string library = "";
// Get the number of admins
var admins = e.WebClientContext.Web.GetAdministrators();
Log.Info("SiteGovernanceJob", "ThreadID = {2} | Site {0} has {1} administrators.", e.Url, admins.Count, Thread.CurrentThread.ManagedThreadId);
// grab reference to list
library = "SiteAssets";
List list = e.WebClientContext.Web.GetListByUrl(library);
if (!e.GetProperty("ScriptFileVersion").Equals("1.0", StringComparison.InvariantCultureIgnoreCase))
{
if (list == null)
{
// grab reference to list
library = "Style%20Library";
list = e.WebClientContext.Web.GetListByUrl(library);
}
if (list != null)
{
// upload js file to list
list.RootFolder.UploadFile("sitegovernance.js", "sitegovernance.js", true);
e.SetProperty("ScriptFileVersion", "1.0");
}
}
if (admins.Count < 2)
{
// Oops, we need at least 2 site collection administrators
e.WebClientContext.Site.AddJsLink(SiteGovernanceJobKey, BuildJavaScriptUrl(e.Url, library));
Console.WriteLine("Site {0} marked as incompliant!", e.Url);
e.SetProperty("SiteCompliant", "false");
}
else
{
// We're all good...let's remove the notification
e.WebClientContext.Site.DeleteJsLink(SiteGovernanceJobKey);
Console.WriteLine("Site {0} is compliant", e.Url);
e.SetProperty("SiteCompliant", "true");
}
e.CurrentRunSuccessful = true;
e.DeleteProperty("LastError");
}
catch(Exception ex)
{
e.CurrentRunSuccessful = false;
e.SetProperty("LastError", ex.Message);
}
}
Der Zustand wird als einzelne serialisierte JSON-Eigenschaft gespeichert, was bedeutet, dass er auch von anderen Anpassungen verwendet werden kann. Wenn der Zeitgeberauftrag beispielsweise den Statuseintrag "SiteCompliant=false" geschrieben hat, kann eine JavaScript-Routine den Benutzer zum Handeln auffordern, da der Zeitgeberauftrag festgestellt hat, dass die Website nicht konform war.
Threading
Das Zeitgeberauftragsframework verwendet standardmäßig Threads zum Parallelisieren der Arbeit. Threading wird sowohl für die Unterwebsiteerweiterung (bei Bedarf) als auch für die Ausführung der eigentlichen Zeitgeberauftragslogik (TimerJobRun-Ereignis ) für jeden Standort verwendet. Die folgenden Eigenschaften können verwendet werden, um die Threadingimplementierung zu steuern:
- UseThreading-Eigenschaft : Ruft einen Wert ab, der angibt, ob Threading verwendet wird, oder legt diesen fest. Standardwert ist true. Legen Sie diesen Wert auf false fest, um alle Aktionen mithilfe des Standard Anwendungsthreads auszuführen.
- MaximumThreads-Eigenschaft : Ruft die Anzahl der Threads ab, die für diesen Zeitgeberauftrag verwendet werden sollen, oder legt sie fest. Gültige Werte sind 2 bis 100. Die möglichen Werte liegen in einem Bereich von 1 bis 998, der Standardwert ist 5. Viele Threads sind nicht unbedingt schneller als nur wenige Threads. Die optimale Anzahl sollte über Tests mithilfe einer Vielzahl von Threadanzahlen abgerufen werden. Es wurde festgestellt, dass der Standardwert von 5 Threads die Leistung in den meisten Szenarien erheblich erhöht.
Einschränkung
Da ein Zeitgeberauftrag Threading verwendet und Zeitgeberauftragsvorgänge in der Regel ressourcenintensive Vorgänge sind, kann eine Zeitgeberauftragsausführung gedrosselt werden. Um die Drosselung ordnungsgemäß zu behandeln, verwenden das Zeitgeberauftragsframework und das gesamte PnP Core die ExecuteQueryRetry-Methode anstelle der Standardmäßigen ExecuteQuery-Methode .
Hinweis
Es ist wichtig, ExecuteQueryRetry in Ihrem Zeitgeberauftragsimplementierungscode zu verwenden.
Parallelitätsprobleme: Verarbeiten aller Unterwebsites einer Websitesammlung im selben Thread
Zeitgeberaufträge können Parallelitätsprobleme haben, wenn mehrere Threads zum Verarbeiten von Unterwebsites verwendet werden.
Nehmen Sie dieses Beispiel: Thread A verarbeitet den ersten Satz von Unterwebsites aus der Websitesammlung 1, und Thread B verarbeitet die restlichen Unterwebsites aus der Websitesammlung 1. Wenn der Zeitgeberauftrag die Unterwebsite und die Stammwebsite (mithilfe des SiteClientContext-Objekts ) verarbeitet, kann ein Parallelitätsproblem vorliegen, da sowohl Thread A als auch Thread B die Stammwebsite verarbeiten.
Um das Parallelitätsproblem zu vermeiden (ohne die Zeitgeberaufträge in einem einzelnen Thread auszuführen), verwenden Sie die GetAllSubSites-Methode innerhalb des Zeitgeberauftrags.
Der folgende Code zeigt, wie die GetAllSubSites-Methode in einem Zeitgeberauftrag verwendet wird:
public class SiteCollectionScopedJob: TimerJob
{
public SiteCollectionScopedJob() : base("SiteCollectionScopedJob")
{
// ExpandSites *must* be false as we'll deal with that at TimerJobEvent level
ExpandSubSites = false;
TimerJobRun += SiteCollectionScopedJob_TimerJobRun;
}
void SiteCollectionScopedJob_TimerJobRun(object sender, TimerJobRunEventArgs e)
{
// Get all the subsites in the site we're processing
IEnumerable<string> expandedSites = GetAllSubSites(e.SiteClientContext.Site);
// Manually iterate over the content
foreach (string site in expandedSites)
{
// Clone the existing ClientContext for the sub web
using (ClientContext ccWeb = e.SiteClientContext.Clone(site))
{
// Here's the timer job logic, but now a single site collection is handled in a single thread which
// allows for further optimization or prevents race conditions
ccWeb.Load(ccWeb.Web, s => s.Title);
ccWeb.ExecuteQueryRetry();
Console.WriteLine("Here: {0} - {1}", site, ccWeb.Web.Title);
}
}
}
}
Protokollierung
Das Zeitgeberauftragsframework verwendet die PnP Core-Protokollierungskomponenten, da es Teil der PnP Core-Bibliothek ist. Um die integrierte PnP Core-Protokollierung zu aktivieren, konfigurieren Sie sie mithilfe der entsprechenden Konfigurationsdatei (app.config oder web.config). Das folgende Beispiel zeigt die erforderliche Syntax:
<system.diagnostics>
<trace autoflush="true" indentsize="4">
<listeners>
<add name="DebugListenter" type="System.Diagnostics.TextWriterTraceListener" initializeData="trace.log" />
<!--<add name="consoleListener" type="System.Diagnostics.ConsoleTraceListener" />-->
</listeners>
</trace>
</system.diagnostics>
Mithilfe der obigen Konfigurationsdatei schreibt das Zeitgeberauftragsframework Protokolle System.Diagnostics.TextWriterTraceListener
in eine Datei namens trace.log im selben Ordner wie der Zeitgeberauftrag .exe. Andere Ablaufverfolgungslistener sind verfügbar, z. B.:
- ConsoleTraceListener schreibt Protokolle in die Konsole.
- Die unter Clouddiagnose – Übernehmen der Kontrolle über Protokollierung und Ablaufverfolgung in Windows Azure beschriebene Methode. Diese Methode verwendet Microsoft.WindowsAzure.Diagnostics. DiagnosticMonitorTraceListener. Weitere Azure-Ressourcen finden Sie hier:
Es wird dringend empfohlen, denselben Protokollierungsansatz für Ihren benutzerdefinierten Zeitgeberauftragscode wie für das Zeitgeberauftragsframework zu verwenden. In Ihrem Zeitgeberauftragscode können Sie die PnP Core Log-Klasse verwenden:
void SiteGovernanceJob_TimerJobRun(object o, TimerJobRunEventArgs e)
{
try
{
string library = "";
// Get the number of admins
var admins = e.WebClientContext.Web.GetAdministrators();
Log.Info("SiteGovernanceJob", "ThreadID = {2} | Site {0} has {1} administrators.", e.Url, admins.Count, Thread.CurrentThread.ManagedThreadId);
// Additional timer job logic...
e.CurrentRunSuccessful = true;
e.DeleteProperty("LastError");
}
catch(Exception ex)
{
Log.Error("SiteGovernanceJob", "Error while processing site {0}. Error = {1}", e.Url, ex.Message);
e.CurrentRunSuccessful = false;
e.SetProperty("LastError", ex.Message);
}
}