Freigeben über


Erstellen von Remotezeitgeberaufträgen in SharePoint

Erstellen Sie Remotezeitgeberaufträge, um SharePoint durch Überwachen und Ergreifen von Maßnahmen auf SharePoint-Daten zu verwalten. Remotezeitgeberaufträge werden nicht auf Ihrem SharePoint-Server ausgeführt. Remotezeitgeberaufträge sind vielmehr geplante Aufgaben, die auf einem anderen Server ausgeführt werden.

Beispiele für die Verwendung von Zeitgeberaufträgen:

  • Governance-Aufgaben, z. B. das Anzeigen einer Meldung auf der Website, wenn bestimmte Kriterien nicht erfüllt werden, oder das Erzwingen von Aufbewahrungsrichtlinien.
  • Ausführung geplanter Prozesse, die prozessorintensiv sind.

Bevor Sie beginnen

Laden Sie zunächst das Core.TimerJobs.Samples-Beispiel-Add-In aus dem Projekt „Office 365-Entwicklermuster und -vorgehensweisen“ auf GitHub herunter.

Hinweis

Der Code in diesem Artikel wird wie besehen und ohne jegliche Garantie zur Verfügung gestellt, gleich ob ausdrücklich oder konkludent, einschließlich jedweder stillschweigenden Gewährleistung der Eignung für einen bestimmten Zweck, Marktgängigkeit oder Nichtverletzung von Rechten.

Um mit der Verwendung der Core.TimerJobs.Samples-Lösung zu beginnen, müssen Sie ein Startprojekt auswählen, z. B. das Projekt „SimpleJob“, indem Sie das Kontextmenü (mit der rechten Maustaste) für Core.TimerJobs.Samples.SimpleJob öffnen, und dann Als Startprojekt festlegen auswählen.

Hinweis

Wenn Sie ein neues Projekt in Visual Studio erstellen, fügen Sie das OfficeDevPnP.Core NuGet-Paket zu Ihrem Projekt hinzu, um einen neuen Remotezeitgeberauftrag zu erstellen. Wählen Sie in Visual Studio Tools>NuGet-Paket-Manager>NuGet-Pakete für Projektmappe verwalten aus.

Planen des Remotezeitgeberauftrags

Ein Zeitgeberauftrag kann so geplant werden, dass er einmal oder als wiederkehrender Auftrag ausgeführt wird. Um den Remotezeitgeberauftrag in Ihrer Produktionsumgebung zu planen, müssen Sie Ihren Code in einer EXE-Datei kompilieren und die EXE-Datei dann mit der Windows-Aufgabenplanung oder einem Microsoft Azure-WebJob ausführen. Weitere Informationen finden Sie unter Bereitstellungsoptionen für Zeitgeberauftrag.

Verwenden des Core.TimerJobs.Samples.SimpleJob-Add-Ins

In Core.TimerJobs.Samples.SimpleJob führt Main in Program.cs die folgenden Schritte aus:

  1. Es wird ein SimpleJob-Objekt erstellt, das von der OfficeDevPnP.Core.Framework.TimerJobs.TimerJob-Basisklasse erbt.

  2. Legt die Office 365-Benutzeranmeldeinformationen fest, die verwendet werden sollen, wenn der Zeitgeberauftrag mithilfe von TimerJob.UseOffice365Authentication ausgeführt wird. Die Benutzeranmeldeinformationen müssen über entsprechenden Zugriff auf die Websitesammlungen verfügen. Weitere Informationen finden Sie unter Authentifizierung.

  3. Es werden Websites hinzugefügt, für die der Zeitgeberauftrag mithilfe von TimerJob.AddSite Aufgaben ausführen soll. Sie können optional die TimerJob.AddSite-Anweisung wiederholen, um mehrere Websites hinzuzufügen, oder alle Websites mithilfe des Platzhalterzeichens * unter einer bestimmten URL hinzufügen. http://contoso.sharepoint.com/sites/* führt beispielsweise den Zeitgeberauftrag auf allen Websites unter dem verwalteten Pfad Websites aus.

  4. Informationen zum Zeitgeberauftrag werden gedruckt, und der Zeitgeberauftrag wird mithilfe von PrintJobSettingsAndRunJob ausgeführt.

     static void Main(string[] args)
             {
                 SimpleJob simpleJob = new SimpleJob();
    
                 // The user credentials must have access to the site collections you supply.
                 simpleJob.UseOffice365Authentication(User, Password);
    
                 // Use the following code if you are using SharePoint Server on-premises. 
                 //simpleJob.UseNetworkCredentialsAuthentication(User, Password, Domain);
    
                 // Add one or more sites that the timer job should work with.
                 simpleJob.AddSite("https://contoso.sharepoint.com/sites/dev");
    
                 // Prints timer job information and then calls Run().
                 PrintJobSettingsAndRunJob(simpleJob);
             }
    

Wenn das SimpleJob-Objekt instanziiert wird, führt der SimpleJob-Konstruktor Folgendes aus:

  1. Er ruft den TimerJob-Basisklassenkonstruktor auf.

  2. Weist den SimpleJob_TimerJobRun-Ereignishandler zur Behandlung der TimerJobRun-Ereignisse zu. SimpleJob_TimerJobRun wird ausgeführt, wenn timerJob.Run aufgerufen wird. Dies wird weiter unten in diesem Artikel ausführlicher beschrieben.

     public SimpleJob() : base("SimpleJob")
             {
                 TimerJobRun += SimpleJob_TimerJobRun;
             }
    

Wenn PrintJobSettingsAndRunJob ausgeführt wird, wird die Ausgabe von TimerJob in das Konsolenfenster geschrieben, und dann wird TimerJob.Run aufgerufen.

 private static void PrintJobSettingsAndRunJob(TimerJob job)
        {
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("************************************************");
            Console.WriteLine("Job name: {0}", job.Name);
            Console.WriteLine("Job version: {0}", job.Version);
            Console.WriteLine("Use threading: {0}", job.UseThreading);
            Console.WriteLine("Maximum threads: {0}", job.MaximumThreads);
            Console.WriteLine("Expand sub sites: {0}", job.ExpandSubSites);
            Console.WriteLine("Authentication type: {0}", job.AuthenticationType);
            Console.WriteLine("Manage state: {0}", job.ManageState);
            Console.WriteLine("SharePoint version: {0}", job.SharePointVersion);
            Console.WriteLine("************************************************");
            Console.ForegroundColor = ConsoleColor.Gray;

            // Run job.
            job.Run();
        }

TimerJob.Run löst TimerJobRun-Ereignisse aus. TimerJob.Run ruft SimpleJob_TimerJobRun in SimpleJob.cs auf, die Sie als Ereignishandler festlegen, um TimerJobRun-Ereignisse im Konstruktor von SimpleJob zu behandeln.

In SimpleJob_TimerJobRun können Sie Ihren benutzerdefinierten Code hinzufügen, den Ihr Zeitgeberauftrag ausführen soll, wenn der Zeitgeberauftrag ausgeführt wird. SimpleJob_TimerJobRun ihren benutzerdefinierten Code auf den Websites aus, die Sie mithilfe von TimerJob.AddSite in Program.cs hinzugefügt haben.

In diesem Codebeispiel verwendet SimpleJob_TimerJobRun den ClientContext aus dem TimerJob , um den Titel der Website in das Konsolenfenster zu schreiben. Wenn mehrere Websites mithilfe von TimerJob.AddSite hinzugefügt wurden, wird für jede Website SimpleJob_TimerJobRun aufgerufen.

 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);
        }

Beispiel: Zeitgeberauftrag für die Erzwingung der Aufbewahrung des Inhaltstyps

Das Core.TimerJobs.Samples.ContentTypeRetentionEnforcementJob-Projekt zeigt, wie Sie SharePoint-Zeitgeberaufträge verwenden können, um Aufbewahrungsrichtlinien für Inhaltstypen zu erzwingen. Geben Sie mithilfe des ContentTypeRetentionPolicyPeriod-Elements in „app.config“ Folgendes an:

  • key, also die Inhaltstyp-ID des Inhaltstyps, für den der Aufbewahrungszeitraum gilt.
  • value, also die Aufbewahrungsdauer in Tagen. Die Aufbewahrungsdauer wird auf alle Listenelemente angewendet, die mithilfe des in key angegebenen Inhaltstyps erstellt wurden.
<ContentTypeRetentionPolicyPeriod>
    <!-- Key is the content type ID, and value is the retention period in days -->
    <!-- Specifies an audio content type should be kept for 183 days -->
    <add key="0x0101009148F5A04DDD49cbA7127AADA5FB792B006973ACD696DC4858A76371B2FB2F439A" value="183" />
    <!-- Specifies a document content type should be kept for 365 days -->   
    <add key="0x0101" value="365" />
</ContentTypeRetentionPolicyPeriod>

ContentTypeRetentionEnforcementJob_TimerJobRun wird als Ereignishandler für das TimerJobRun-Ereignis festgelegt. Wenn TimerJob.Run in Program.cs aufgerufen wird, führt ContentTypeRetentionEnforcementJob_TimerJobRun die folgenden Schritte auf jeder Website aus, die mithilfe von TimerJob.AddSite in Program.cs hinzugefügt wurde:

  1. Ruft alle Dokumentbibliotheken auf der Website ab.
  2. Für jede Dokumentbibliothek auf der Website werden die Konfigurationsinformationen gelesen, die unter ContentTypeRetentionPolicyPeriod in „app.config“ angegeben sind. Für jedes Paar von Inhaltstyp-ID und Aufbewahrungsdauer, das aus „app.config“ gelesen wurde, wird ApplyRetentionPolicy aufgerufen.
 void ContentTypeRetentionEnforcementJob_TimerJobRun(object sender, TimerJobRunEventArgs e)
        {
            try
            {
                Log.Info("ContentTypeRetentionEnforcementJob", "Scanning web {0}", e.Url);

                // Get all document libraries. Lists are excluded.
                var documentLibraries = GetAllDocumentLibrariesInWeb(e.WebClientContext, e.WebClientContext.Web);

                // Iterate through all document libraries.
                foreach (var documentLibrary in documentLibraries)
                {
                    Log.Info("ContentTypeRetentionEnforcementJob", "Scanning library {0}", documentLibrary.Title);

                    // Iterate through configured content type retention policies specified in app.config.
                    foreach (var contentTypeName in configContentTypeRetentionPolicyPeriods.Keys)
                    {
                        var retentionPeriods = configContentTypeRetentionPolicyPeriods.GetValues(contentTypeName as string);
                        if (retentionPeriods != null)
                        {
                            var retentionPeriod = int.Parse(retentionPeriods[0]);
                            ApplyRetentionPolicy(e.WebClientContext, documentLibrary, contentTypeName, retentionPeriod);
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                Log.Error("ContentTypeRetentionEnforcementJob", "Exception processing site {0}. Exception is {1}", e.Url, ex.Message);
            }
        }

ApplyRetentionPolicy erzwingt die Aktionen der benutzerdefinierten Aufbewahrungsrichtlinie durch:

  1. Berechnen von ValidationDate. Die ApplyRetentionPolicy-Methode erzwingt Aktionen der Aufbewahrungsrichtlinie in Dokumenten, die vor ValidationDate geändert wurden. ValidationDate wird dann als CAML-Datum formatiert und CamlDate zugewiesen.

  2. Ausführen einer CAML-Abfrage zum Filtern von Dokumenten in der Dokumentbibliothek basierend auf der Inhaltstyp-ID, die in „app.config“ angegeben wurde, und bei denen das Datum Geändert von kleiner ist als camlDate.

  3. Bei jedem Listenelement werden benutzerdefinierte Aufbewahrungsaktionen in den Dokumenten mithilfe von benutzerdefiniertem Code angewendet.

private void ApplyRetentionPolicy(ClientContext clientContext, List documentLibrary, object contentTypeId, int retentionPeriodDays)
        {
            // Calculate validation date. You need to enforce the retention policy on any document modified before validation date.
            var validationDate = DateTime.Now.AddDays(-retentionPeriodDays);
            var camlDate = validationDate.ToString("yyyy-MM-ddTHH:mm:ssZ");

            // Get old documents in the library that match the content type.
            if (documentLibrary.ItemCount > 0)
            {
                var camlQuery = new CamlQuery();
                
                camlQuery.ViewXml = String.Format(
                    @"<View>
                        <Query>
                            <Where><And>
                                <BeginsWith><FieldRef Name='ContentTypeId'/><Value Type='ContentTypeId'>{0}</Value></BeginsWith>
                                <Lt><FieldRef Name='Modified' /><Value Type='DateTime'>{1}</Value></Lt>
                            </And></Where>
                        </Query>
                    </View>", contentTypeId, camlDate);

                var listItems = documentLibrary.GetItems(camlQuery);
                clientContext.Load(listItems,
                    items => items.Include(
                        item => item.Id,
                        item => item.DisplayName,
                        item => item.ContentType));

                clientContext.ExecuteQueryRetry(); 

                foreach (var listItem in listItems)
                {
                    Log.Info("ContentTypeRetentionEnforcementJob", "Document '{0}' has been modified earlier than {1}. Retention policy will be applied.", listItem.DisplayName, validationDate);
                    Console.WriteLine("Document '{0}' has been modified earlier than {1}. Retention policy will be applied.", listItem.DisplayName, validationDate);
                    
                    // Apply your custom retention actions here. For example, archiving documents, or starting a disposition workflow.
                }
            }
        }

Beispiel: Governance-Zeitgeberauftrag

Das Core.TimerJobs.Samples.GovernanceJob-Projekt verwendet Zeitgeberaufträge, um sicherzustellen, dass zwei Administratoren Ihren Websitesammlungen zugewiesen werden; ist dies nicht der Fall, wird eine Benachrichtigung auf der Website angezeigt.

SiteGovernanceJob_TimerJobRun wird als Ereignishandler für das TimerJobRun-Ereignis festgelegt. Wenn TimerJob.Run in Program.cs aufgerufen wird, führt SiteGovernanceJob_TimerJobRun die folgenden Schritte für jede Websitesammlung aus, die mithilfe von TimerJob.AddSite in Program.cs hinzugefügt wurde:

  1. Ruft die Anzahl von Administratoren ab, die der Websitesammlung mithilfe der Erweiterungsmethode GetAdministrators hinzugefügt wurde, die Teil von OfficeDevPnP.Core ist.

  2. Lädt die JavaScript-Datei in die SiteAssets-Liste- oder die Liste der Formatvorlagenbibliothek mithilfe von UploadFile hoch, was Teil von OfficeDevPnP.Core ist.

  3. Wenn die Website weniger als zwei Administratoren hat, fügt AddJSLink eine Benachrichtigung zu einer Website mithilfe von JavaScript hinzu. Weitere Informationen finden Sie unter Anpassen Ihrer SharePoint-Website mithilfe von JavaScript.

  4. Wenn die Website zwei oder mehr Administratoren hat, wird die Benachrichtigung mithilfe von DeleteJsLink entfernt.

void SiteGovernanceJob_TimerJobRun(object o, TimerJobRunEventArgs e)
        {
            try
            {
                string library = "";

                // Get the number of administrators.
                var admins = e.WebClientContext.Web.GetAdministrators();

                Log.Info("SiteGovernanceJob", "ThreadID = {2} | Site {0} has {1} administrators.", e.Url, admins.Count, Thread.CurrentThread.ManagedThreadId);

                // Get a reference to the list.
                library = "SiteAssets";
                List list = e.WebClientContext.Web.GetListByUrl(library);

                if (!e.GetProperty("ScriptFileVersion").Equals("1.0", StringComparison.InvariantCultureIgnoreCase))
                {
                    if (list == null)
                    {
                        // Get a reference to the 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)
                {
                    // Show notification message because you need at least two 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
                {
                    // Remove the notification message because two administrators are assigned.
                    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)
            {
                Log.Error("SiteGovernanceJob", "Error while processing site {0}. Error = {1}", e.Url, ex.Message);
                e.CurrentRunSuccessful = false;
                e.SetProperty("LastError", ex.Message);
            }
        }

Siehe auch