Compartir a través de


Crear trabajos del temporizador remoto en SharePoint

Cree trabajos del temporizador remoto para administrar SharePoint mediante la supervisión y la realización de acciones sobre datos de SharePoint. Los trabajos del temporizador remoto no se ejecutan en el servidor de SharePoint. En su lugar, los trabajos del temporizador remoto son tareas programadas que se ejecutan en otro servidor.

Ejemplos de cómo se usan los trabajos del temporizador:

  • Realización de tareas de gobierno, como mostrar un mensaje en el sitio cuando no se cumplan determinados criterios o aplicar directivas de retención.
  • Ejecutar procesos programados que exijan un uso intensivo del procesador.

Antes de empezar

Para empezar, descargue el complemento de ejemplo Core.TimerJobs.Samples desde el proyecto Modelos y prácticas de desarrollo de Office 365 en GitHub.

Nota:

El código de este artículo se proporciona tal cual, sin garantía de ningún tipo, expresa o implícita, incluidas las garantías implícitas de aptitud para un propósito particular, comerciabilidad o ausencia de infracción.

Para empezar a usar la solución de Core.TimerJobs.Samples, debe seleccionar un proyecto de inicio, por ejemplo, el proyecto de SimpleJob. Para ello, abra el menú contextual (haciendo clic con el botón derecho) de Core.TimerJobs.Samples.SimpleJob y, a continuación, elija Establecer como proyecto de inicio.

Nota:

Al crear un nuevo proyecto en Visual Studio, para empezar a crear el nuevo trabajo del temporizador remoto, agregue el paquete NuGet OfficeDevPnP.Core al proyecto. En Visual Studio, elija HERRAMIENTAS>Administrador de paquetes NuGet>Administrar paquetes NuGet para la solución.

Programar el trabajo del temporizador remoto

Un trabajo del temporizador puede programarse para ejecutarse una vez o puede ser una tarea periódica. Para programar el trabajo del temporizador remoto en su entorno de producción, debe compilar el código en un archivo .exe y, a continuación, ejecutar el archivo .exe mediante el Programador de tareas de Windows o un WebJob de Microsoft Azure. Para obtener más información, vea Opciones de implementación de trabajo del temporizador.

Usar el complemento de Core.TimerJobs.Samples.SimpleJob

En Core.TimerJobs.Samples.SimpleJob, Principal en Program.cs realiza los siguientes pasos:

  1. Crea un objeto SimpleJob, que se hereda de la clase base OfficeDevPnP.Core.Framework.TimerJobs.TimerJob.

  2. Establece las credenciales de usuario de Office 365 para usar cuando se ejecuta el trabajo del temporizador mediante el uso de TimerJob.UseOffice365Authentication. Las credenciales del usuario deben tener el acceso adecuado a las colecciones de sitios. Puede obtener más información en Autenticación.

  3. Agrega sitios en los que el trabajo del temporizador debe realizar las tareas con TimerJob.AddSite. De forma opcional, puede repetir la instrucción TimerJob.AddSite para agregar más de un sitio o agregar todos los sitios en una dirección URL determinada mediante el carácter comodín *. Por ejemplo, http://contoso.sharepoint.com/sites/* ejecuta el trabajo del temporizador en todos los sitios bajo la ruta de acceso administrada de sitios.

  4. Imprime información sobre el trabajo del temporizador y ejecuta el trabajo del temporizador con PrintJobSettingsAndRunJob.

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

Cuando se crea una instancia del objeto SimpleJob, el constructor SimpleJob:

  1. Llama al constructor de clase base del TimerJob.

  2. Asigna el controlador de eventos SimpleJob_TimerJobRun para controlar los eventos TimerJobRun . SimpleJob_TimerJobRun se ejecuta cuando se realiza una llamada a TimerJob.Run, que se describe con más detalle más adelante en este artículo.

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

Cuando PrintJobSettingsAndRunJob se ejecuta, el resultado de TimerJob se escribe en la ventana de la consola y luego se llama a TimerJob.Run.

 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 provoca los eventos de TimerJobRun. TimerJob.Run llama a SimpleJob_TimerJobRun en SimpleJob.cs, que se establece como controlador de eventos para controlar eventos TimerJobRun en el constructor de SimpleJob.

En SimpleJob_TimerJobRun, puede agregar el código personalizado que desea que el trabajo del temporizador realice cuando se ejecute el trabajo del temporizador. SimpleJob_TimerJobRun ejecuta el código personalizado en los sitios que agregó mediante TimerJob.AddSite en Program.cs.

En este ejemplo de código, SimpleJob_TimerJobRun usa ClientContext de TimerJob para escribir el título del sitio en la ventana de consola. Si se agregaron varios sitios mediante TimerJob.AddSite, se llama a SimpleJob_TimerJobRun para cada sitio.

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

Ejemplo: trabajo del temporizador de cumplimiento de retención del tipo de contenido

El proyecto Core.TimerJobs.Samples.ContentTypeRetentionEnforcementJob muestra cómo puede usar los trabajos del temporizador de SharePoint para aplicar directivas de retención de tipos de contenido. Usando el elemento ContentTypeRetentionPolicyPeriod en app.config, especifique:

  • key, que es el identificador de tipo de contenido del tipo de contenido al que se aplica el período de retención.
  • value, que es el período de retención en días. El período de retención se aplica a todos los elementos de lista creados con el tipo de contenido especificado en key.
<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 se establece como controlador de eventos para el evento TimerJobRun . Cuando se llama a TimerJob.Run en Program.cs, ContentTypeRetentionEnforcementJob_TimerJobRun realiza los pasos siguientes en cada sitio que se agregó mediante TimerJob.AddSite en Program.cs:

  1. Obtiene todas las bibliotecas de documentos del sitio.
  2. Para cada biblioteca de documentos del sitio, lee la información de configuración especificada en ContentTypeRetentionPolicyPeriod en app.config. Para cada par de ID de tipo de contenido y período de retención leído de app.config, se llama a ApplyRetentionPolicy.
 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 aplica las acciones de la directiva de retención personalizada mediante:

  1. El cálculo de validationDate. El método ApplyRetentionPolicy aplica las acciones de la directiva de retención en los documentos que se modificaron antes de validationDate. Después, se da formato a validationDate como fecha CAML y se asigna a camlDate.

  2. Ejecución de una consulta CAML para filtrar documentos en la biblioteca de documentos con el identificador de tipo de contenido, que se especifica en app.config, y donde la fecha de Modificado por es menor que camlDate.

  3. Para cada elemento de lista, la aplicación de las acciones de retención personalizadas a realizar en los documentos mediante código personalizado.

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.
                }
            }
        }

Ejemplo: Trabajo del temporizador de gobierno

El proyecto Core.TimerJobs.Samples.GovernanceJob usa trabajos del temporizador para asegurarse de que se asignan dos administradores a las colecciones de sitios y, si no, muestra un mensaje de notificación en el sitio.

SiteGovernanceJob_TimerJobRun se establece como controlador de eventos para el evento TimerJobRun . Cuando se llama a TimerJob.Run en Program.cs, SiteGovernanceJob_TimerJobRun realiza los pasos siguientes en cada colección de sitios que se agregó mediante TimerJob.AddSite en Program.cs:

  1. Obtiene el número de administradores asignados a la colección de sitios mediante el método de extensión GetAdministrators, que forma parte de OfficeDevPnP.Core.

  2. Carga el archivo JavaScript en la lista de biblioteca de estilos o SiteAssets mediante UploadFile, que es parte de OfficeDevPnP.Core.

  3. Si el sitio tiene menos de dos administradores, AddJSLink agrega un mensaje de notificación a un sitio mediante JavaScript. Puede obtener más información en Personalizar su interfaz de usuario del sitio de SharePoint mediante JavaScript.

  4. Si el sitio tiene dos o más administradores, se quita el mensaje de notificación usando DeleteJsLink.

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

Vea también