Criar trabalhos do temporizador remotos no SharePoint
Crie trabalhos remotos do temporizador para gerenciar o SharePoint monitorando e executando uma ação com os dados do SharePoint. Os trabalhos remotos do temporizador não são executados no servidor do SharePoint. Em vez disso, os trabalhos remotos do temporizador são tarefas agendadas executadas em outro servidor.
Exemplos de como os trabalhos do temporizador são usados:
- Executar tarefas de governança, como exibir uma mensagem no site quando determinados critérios não forem atendidos ou aplicar políticas de retenção.
- Executar os processos agendados que exigem uso intensivo do processador.
Antes de começar
Para começar, faça o download do suplemento de exemplo Core.TimerJobs.Samples no projeto Padrões e Práticas do Desenvolvedor do Office 365 no GitHub.
Observação
The code in this article is provided as-is, without warranty of any kind, either express or implied, including any implied warranties of fitness for a particular purpose, merchantability, or non-infringement.
Para começar a usar a solução Core.TimerJobs.Samples, selecione um projeto de inicialização, por exemplo, o projeto SimpleJob, abrindo o menu de atalho para (clicando com o botão direito do mouse) Core.TimerJobs.Samples.SimpleJob, depois escolhendo Definir como Projeto de Inicialização.
Observação
Ao criar um novo projeto no Visual Studio, para começar a criar seu novo trabalho de temporizador remoto, adicione o pacote OfficeDevPnP.Core NuGet ao projeto. No Visual Studio, escolha FERRAMENTAS>Gerenciador de Pacotes NuGet>Gerenciar Pacotes NuGet para a Solução.
Agendar o trabalho de temporizador remoto
Um trabalho de temporizador pode ser agendado para ser executado uma vez ou pode ser um trabalho recorrente. Para agendar o trabalho remoto em seu ambiente de produção, você precisa compilar o código em um arquivo .exe e executar o arquivo .exe usando Agendador de tarefas do Windows ou um WebJob do Microsoft Azure. Para saber mais, confira Opções de implantação de trabalho de temporizador.
Usar o suplemento Core.TimerJobs.Samples.SimpleJob
No Core.TimerJobs.Samples.SimpleJob, Main em Program cs executa as seguintes etapas:
Cria um objeto SimpleJob, que herda da classe base OfficeDevPnP.Core.Framework.TimerJobs.TimerJob.
Define as credenciais de usuário do Office 365 para usar ao executar o trabalho de temporizador usando TimerJob.UseOffice365Authentication. As credenciais de usuário devem ter o acesso apropriado ao conjuntos de sites. Saiba mais em Autenticação.
Adiciona os sites em que o trabalho de temporizador deve realizar tarefas usando TimerJob.AddSite. Você também pode repetir a instrução TimerJob.AddSite para adicionar mais de um site ou adicionar todos os sites em uma URL específica usando o caractere curinga
*
. Por exemplo,http://contoso.sharepoint.com/sites/*
executa o trabalho de temporizador em todos os sites no caminho gerenciado sites.Imprime informações do trabalho de temporizador e executa o trabalho de temporizador usando 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); }
Quando o objeto SimpleJob é instanciado, o construtor SimpleJob:
Chama o construtor de classe base TimerJob.
Atribui o manipulador de eventos SimpleJob_TimerJobRun para manipular os eventos TimerJobRun . SimpleJob_TimerJobRun é executado quando uma chamada é feita para TimerJob.Run, que é descrita com mais detalhes posteriormente neste artigo.
public SimpleJob() : base("SimpleJob") { TimerJobRun += SimpleJob_TimerJobRun; }
Quando PrintJobSettingsAndRunJob é executado, a saída do TimerJob é gravada na janela do console e TimerJob.Run é chamado.
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 gera eventos TimerJobRun. TimerJob.Run chama SimpleJob_TimerJobRun em SimpleJob.cs, que você define como o manipulador de eventos para lidar com eventos TimerJobRun no construtor do SimpleJob.
Em SimpleJob_TimerJobRun, você pode adicionar seu código personalizado que deseja que seu trabalho de temporizador execute quando o trabalho do temporizador for executado. SimpleJob_TimerJobRun executa seu código personalizado nos sites adicionados usando TimerJob.AddSite em Program.cs.
Neste exemplo de código, SimpleJob_TimerJobRun usa o ClientContext do TimerJob para gravar o título do site na janela do console. Se vários sites foram adicionados usando TimerJob.AddSite, SimpleJob_TimerJobRun será chamado para cada site.
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);
}
Exemplo: trabalho de temporizador para aplicação de retenção de tipo de conteúdo
O projeto Core.TimerJobs.Samples.ContentTypeRetentionEnforcementJob mostra como você pode usar os trabalhos de temporizador do SharePoint para impor políticas de retenção tipos de conteúdo. Usando o elemento ContentTypeRetentionPolicyPeriod em app.config, especifique:
- key, qual é a ID do tipo de conteúdo ao qual o período de retenção se aplica.
- value, que é o período de retenção em dias. O período de retenção é aplicado a todos os itens de lista criados usando o tipo de conteúdo especificado em 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 é definido como o manipulador de eventos do evento TimerJobRun . Quando TimerJob.Run é chamado em Program.cs, ContentTypeRetentionEnforcementJob_TimerJobRun executa as seguintes etapas em cada site que foi adicionado usando TimerJob.AddSite em Program.cs:
- Obtém todas as bibliotecas de documentos do site.
- Para cada biblioteca de documentos do site, lê as informações de configuração especificadas em ContentTypeRetentionPolicyPeriod no app.config. Para cada par de ID de tipo de conteúdo e período de retenção lido em app.config, ApplyRetentionPolicy é chamado.
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 impõe suas ações de política de retenção personalizadas da seguinte forma:
Calcula a validationDate. O método ApplyRetentionPolicy aplica ações da política de retenção em documentos modificados antes da validationDate. validationDate é formatado como uma data CAML e atribuído a camlDate.
Executa uma consulta CAML para filtrar documentos na biblioteca de documentos com base na ID do tipo de conteúdo, especificada em app.config, e em que a data Modified By é menor que a camlDate.
Para cada item de lista, aplica ações de retenção personalizadas a serem realizadas nos documentos usando um 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.
}
}
}
Exemplo: trabalho de governança do temporizador
O projeto Core.TimerJobs.Samples.GovernanceJob usa trabalhos de temporizador para garantir que dois administradores sejam atribuídos aos seus conjuntos de sites e, caso contrário, exibir uma mensagem de notificação no site.
SiteGovernanceJob_TimerJobRun é definido como o manipulador de eventos do evento TimerJobRun . Quando TimerJob.Run é chamado em Program.cs, SiteGovernanceJob_TimerJobRun executa as seguintes etapas em cada coleção de sites que foi adicionada usando TimerJob.AddSite em Program.cs:
Obtém o número de administradores atribuídos ao conjunto de sites usando o método de extensão GetAdministrators, que faz parte de OfficeDevPnP.Core.
Carrega o arquivo JavaScript na lista SiteAssets ou Style Library usando UploadFile, que faz parte de OfficeDevPnP.Core.
Se o site tiver menos de dois administradores, AddJSLink adicionará uma mensagem de notificação para um site, usando JavaScript. Saiba mais em Personalizar a IU do site do SharePoint usando JavaScript.
Se o site tiver dois ou mais administradores, a mensagem de notificação será removida 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);
}
}