Partager via


Procédure : exécuter le code sur tous les serveurs Web

Dernière modification : lundi 19 avril 2010

S’applique à : SharePoint Foundation 2010

De nombreux scénarios de développement, notamment ceux qui possèdent une fonctionnalité administrative, nécessitent que le même code s’exécute sur chaque serveur Web frontal d’une batterie. Par exemple, tous les serveurs Web frontaux d’une batterie Microsoft SharePoint Foundation doivent être configurés et mis en service de façon identique, du moins en ce qui concerne leur façon de répondre aux demandes HTTP. Ainsi, la modification d’un paramètre d’un fichier web.config doit-elle s’appliquer à tous les serveurs Web frontaux. Autre exemple, un assembly faisant partie d’une solution de batterie doit être déployé sur le Global Assembly Cache (GAC) de chaque serveur Web frontal.

Pour de nombreux types de tâche de configuration et de déploiement, SharePoint Foundation fournit les API conçues à dessein et qui garantissent que les serveurs demeurent synchronisés. Par exemple, la classe SPWebConfigModification fournit les fonctionnalités pour modifier les paramètres de la pile des fichiers web.config. Pour plus d’informations, voir Comment : ajouter et supprimer par programme des paramètres Web.config. De même, quand vous déployez une solution de batterie, que ce soit dans l’application Administration centrale ou le SharePoint Management Shell, tout assembly qui fait partie de la solution est déployé sur le Global Assembly Cache de chaque serveur Web frontal. Vous pouvez créer une fonctionnalité de déploiement de solution de batterie personnalisée avec la méthode SPSolution.Deploy().

Toutes les API conçues à dessein utilise les travaux du minuteur SharePoint Foundation pour effectuer leur propre travail. Les travaux du minuteur sont ainsi nommés, parce que chacun peut être défini de façon à s’exécuter à un moment défini, que ce soit dans le futur ou immédiatement à la création. Cependant, ils peuvent être aussi appelés travaux multiserveur parce qu’ils peuvent être définis pour s’exécuter sur plusieurs serveurs Web, y compris tous les serveurs Web frontaux, ou sur un serveur spécifique. Lorsque vous avez besoin qu’une fonction s’exécute sur tous les serveurs Web frontaux et qu’il n’existe aucune API conçue à dessein pour la fonction, vous pouvez recourir aux API des travaux du minuteur. Cette rubrique explique comment procéder.

Notes

La distinction entre un serveur Web frontal et un serveur d’applications revêt un aspect plus notionnel dans SharePoint Foundation 2010 que dans les versions antérieures du produit. À une exception près, la totalité de SharePoint Foundation est installé sur tous les serveurs, quel que soit leur statut en tant que serveurs d’application ou serveurs Web frontaux. (L’exception concerne le serveur qui héberge la base de données Microsoft SQL Server pour la batterie. Généralement, SharePoint Foundation n’est pas du tout installé sur cet ordinateur. Par conséquent, dans la totalité de cet article, l’expression « tous les serveurs » exclut les serveurs dédiés de base de données sur lesquels SharePoint Foundation n’est pas installé.) En règle générale, un serveur SharePoint Foundation est un serveur Web frontal si le service application Web Microsoft SharePoint Foundation s’y exécute ; sinon, il s’agit d’un serveur d’applications.

Pour définir un travail du minuteur

  1. Dans Visual Studio, démarrez un projet SharePoint vide. Créez-le comme solution de batterie, pas comme solution en bac à sable (sandbox).

  2. Sélectionnez le nom du projet dans l’Explorateur de solutions, puis assurez-vous que Inclure un assembly dans le package du volet Propriétés ait la valeur true.

  3. Ajoutez un fichier de classe C# ou Visual Basic au projet.

  4. Ouvrez le fichier de classe et ajoutez les instructions using (Imports en Visual Basic) pour les espaces de noms Microsoft.SharePoint et Microsoft.SharePoint.Administration. Il se peut que vous ayez besoin d’ajouter d’autres instructions using selon les espaces de noms appelés par le code que vous voulez exécuter sur tous les serveurs. Pour l’exemple d’exécution de cette rubrique, ajoutez les instructions using pour System.Xml.Linq, System.Xml.XPath, System.IO et System.Runtime.InteropServices.

  5. Modifiez l’espace de noms pour vous conformer aux Conventions de dénomination des espaces de noms (éventuellement en anglais) ; par exemple, Contoso.SharePoint.Administration.

  6. Modifiez la déclaration de la classe pour spécifier qu’elle hérite de SPJobDefinition ou d’une classe qui dérive de SPJobDefinition.

  7. Complétez la déclaration de classe avec un attribut GuidAttribute. Il s’agit d’un impératif pour toute classe qui dérive directement ou indirectement de SPPersistedObject.

  8. Ajoutez un constructeur par défaut (sans paramètre) à la classe qui appelle simplement le constructeur de base.

  9. Ajoutez un constructeur avec les paramètres de types String, SPWebApplication, SPServer et SPJobLockType. Son implémentation doit appeler le constructeur de base SPJobDefinition(String, SPWebApplication, SPServer, SPJobLockType). À ce stade, votre code C# doit se présenter tel que ci-après.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Administration;
    
    using System.Xml.Linq;
    using System.Xml.XPath;
    using System.IO; 
    using System.Runtime.InteropServices;
    
    namespace Contoso.SharePoint.Administration
    {
        [Guid("9573FAD9-ED89-45E8-BD8B-6A5034E03895")]
        public class MyTimerJob : SPJobDefinition
        {
            public MyTimerJob() : base() { }
    
            public MyTimerJob(String name, SPWebApplication wApp, SPServer server, SPJobLockType lockType)
                : base(name, wApp, server, lockType) { }
        }
    }
    

    Notes

    Si vous voulez qu’un travail s’exécute sur tous les serveurs, y compris les serveurs d’applications, votre classe doit dériver de SPServiceJobDefinition. Passez le service du minuteur (SPFarm.Local.TimerService) comme paramètre SPService du constructeur SPServiceJobDefinition(String, SPService).

  10. Ajoutez les substitutions des propriétés DisplayName et Description. La propriété DisplayName est le nom convivial du travail qui apparaît dans les définitions de travaux, les travaux planifiés et les listes de l’historique des travaux dans l’application Administration centrale. Description est une description du travail. Pour des raisons de simplicité, dans l’exemple ci-après, sont affectées des chaînes littérales. Dans un scénario plus réel, pensez à affecter à chaque propriété une chaîne localisée.

    public override string DisplayName
    {
        get
        {
            // TODO: return a localized name
            return "Add Contoso Mobile Adapter";
        }
    }
    
    public override string Description
    {
        get
        {
            // TODO: return a localized description
            return "Adds a mobile adapter for Contoso's voting Web Part.";
        }
    }
    
  11. Ajoutez à la classe une substitution de la méthode Execute(Guid).

    public override void Execute(Guid targetInstanceId)
    {
        // INSERT HERE CODE THAT SHOULD RUN ON ALL SERVERS.
    }
    
  12. L’implémentation de la méthode se compose simplement du code que vous voulez exécuter sur tous les serveurs Web frontaux. Ce code est appelé par le service Minuteur SharePoint 2010, qui doit s’exécuter sur tous les serveurs SharePoint Foundation de la batterie. La méthode Execute(Guid) est appelée par le service du minuteur lorsque le travail est en cours d’exécution et elle s’exécute dans le contexte utilisateur du service du minuteur.Dans une installation SharePoint Foundation à serveur unique, cet utilisateur est généralement Service réseau. Cependant, le cas intéressant est celui d’une batterie multiserveur, où le service du minuteur s’exécute dans le contexte du même compte d’utilisateur de domaine que celui que la batterie utilise pour lire les bases de données de contenu et de configuration, et y écrire. Cet utilisateur n’est administrateur système sur aucun serveur, mais il est membre du groupe d’utilisateurs WSS_ADMIN_WPG sur tous les serveurs. Il possède les droits de lecture, d’écriture et d’exécution sur les dossiers de l’arborescence %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\ et de l’arborescence c:\Inetpub\wwwroot\wss.

    Dans cet article, nous imaginons un scénario au sein duquel vous avez créé un adaptateur WebPart mobile à utiliser sur la version mobile des pages de composants WebPart. Il est nécessaire d’inscrire l’adaptateur dans le fichier compat.browser de l’application Web. Ce fichier se trouve dans le dossier C:\Inetpub\wwwroot\wss\VirtualDirectories\numéro_port\App_Browsers, où numéro_port désigne le numéro de port de l’application Web, tel que « 80 » par exemple. Chaque serveur Web frontal possède sa propre copie du fichier et toutes les copies doivent être modifiées à l’identique. Le code suivant inscrit l’adaptateur dans le fichier compat.browser de chaque serveur sur lequel s’exécute le travail du minuteur. (Vous apprendrez, plus bas dans cet article, à vous assurer que le travail s’exécute sur tous les serveurs.)

    ConseilConseil

    Pour des raisons de simplicité, cet exemple ne modifie le compat.browser que pour la zone d’URL par défaut. Dans un scénario plus réel, pensez à parcourir la totalité des membres de IisSettings.

    public override void Execute(Guid targetInstanceId)
    {
        // Set the path to the file. The code that creates the MyTimerJob object associates
        // the job with a Web application.
        String pathToCompatBrowser = this.WebApplication.IisSettings[SPUrlZone.Default].Path 
                                   + @"\App_Browsers\compat.browser";
    
        XElement compatBrowser = XElement.Load(pathToCompatBrowser);
    
        // Get the node for the default browser.
        XElement controlAdapters = compatBrowser.XPathSelectElement("./browser[@refID = \"default\"]/controlAdapters");
    
        // Create and add the markup.
        XElement newAdapter = new XElement("adapter");
        newAdapter.SetAttributeValue("controlType", 
            "Contoso.SharePoint.WebPartPages.VotingWebPart, Contoso, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ffec2e2af2b4c675");
        newAdapter.SetAttributeValue("adapterType",
            "Contoso.SharePoint.WebPartPages.VotingWebPartMobileAdapter, Contoso, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ffec2e2af2b4c675");
        controlAdapters.Add(newAdapter);
    
        // Overwrite the old version of compat.browser with your new version.
        compatBrowser.Save(pathToCompatBrowser);
    }
    
  13. Sélectionnez Déployer la solution dans le menu Visual Studio Générer. Si la propriété URL du site du projet SharePoint vide de Visual Studio pointe vers une batterie SharePoint Foundation à serveur unique, cette action compile l’assembly, l’inclut dans un fichier de solution SharePoint Foundation (wsp), charge le package sur la galerie de solutions de la batterie et déploie l’assembly sur le GAC. Cependant, dans le cadre de cet article, le cas intéressant est celui du déploiement sur une batterie multiserveur. Vous pouvez définir la propriété URL du site pour qu’elle pointe vers cette batterie, mais dans cette situation, le fait de cliquer sur Déployer la solution ne déclenche aucune action après le chargement de la solution sur la galerie de solutions de la batterie. À partir de là, vous devez déployer la solution. Une solution consiste à la déployer directement depuis la galerie dans l’application Administration centrale. Vous pouvez également utiliser SharePoint Management Shell. Une autre option consiste à sélectionner Package dans le menu Visual Studio Générer. Cette action compile l’assembly et l’inclut dans un package. Vous pouvez ensuite installer le package sur la galerie de solutions de la batterie et le déployer à l’aide de SharePoint Management Shell. Quelle que soit la technique que vous utilisiez, sur une batterie multiserveur, l’étape du déploiement installe l’assembly sur le GAC de tous les serveurs Web frontaux.

Création d’une instance d’un travail de minuteur

Après que l’assembly qui définit votre type de travail de minuteur a été déployé sur tous les serveurs, vous pouvez, par programme, créer et planifier des instances du travail du minuteur. Le code correspondant peut être inclus dans une grande diversité de contextes de développement. Si le travail du minuteur personnalisé fait partie d’une solution que vous déployez en tant que fonctionnalité SharePoint Foundation, vous pouvez inclure le code de création du travail dans une substitution de la méthodeFeatureActivated(SPFeatureReceiverProperties) d’un récepteur de fonctionnalité. (La fonctionnalité doit avoir comme étendue la batterie ou l’application Web.) Une autre possibilité consiste à étendre l’application Administration centrale avec une action personnalisée qui crée le travail. Vous pouvez aussi créer une applet de commande PowerShell qui puisse s’exécuter dans SharePoint Management Shell. Dans cet article, nous utilisons une application console simple. Quel que soit l’emplacement où se trouve votre code de création du travail, il doit s’exécuter dans le contexte utilisateur d’un administrateur de batterie.

Les tâches principales que le code doit accomplir sont les suivantes : construire un objet de votre type de travail de minuteur personnalisé, l’associer à une application Web et définir sa propriété Schedule.

Pour créer et planifier un travail de minuteur

  1. Démarrez un projet d’application console dans Visual Studio. Il peut s’agir d’un deuxième projet au sein de la même solution Visual Studio que votre projet de travail de minuteur ou d’une solution Visual Studio entièrement distincte. Chacune des approches possède ses propres avantages et inconvénients. Dans cette rubrique, nous considérons qu’est utilisée une solution Visual Studio entièrement distincte.

  2. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nom du projet et sélectionnez Propriétés.

  3. Sous l’onglet Application, assurez-vous que le Framework cible est .NET Framework 3.5.

  4. Sous l’onglet Générer, assure-vous que la Plateforme cible est x64 ou Any CPU. Pour plus d’informations sur le choix, voir Procédure : définir le Framework et l’unité centrale cibles adéquats.

  5. Cliquez sur le bouton Enregistrer tous les fichiers dans le menu.

  6. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le nom du projet et sélectionnez Ajouter une référence. Utilisez l’onglet Projets ou Parcourir pour ajouter une référence à l’assembly créé dans la procédure ci-dessus.

  7. Ajoutez une référence aux assemblys Microsoft.SharePoint et Microsoft.SharePoint.Security.

  8. Ouvrez le fichier de code et ajoutez les instructions using (Imports dans Visual Basic) pour les espaces de noms Microsoft.SharePoint et Microsoft.SharePoint.Administration.

  9. Modifiez l’espace de noms pour qu’il corresponde à celui que vous avez utilisé pour votre travail de minuteur personnalisé dans la procédure ci-dessus, ou utilisez un espace de noms différent, mais ajoutez une instruction using pour l’espace de noms dans lequel votre travail de minuteur personnalisé est déclaré.

  10. Ajoutez le code suivant à la méthode Main :

    // Get a reference to the Web application for which you want to register the mobile Web Part adapter.
    SPWebApplication webApp = SPWebApplication.Lookup(new Uri("https://localhost/"));
    

    Il ne s’agit que d’un moyen d’obtenir une référence à une application Web. Pour plus d’informations, voir Obtention de références aux sites, applications Web et autres objets clés.

  11. Ajoutez le code suivant à la méthode Main :

    // Create the timer job.
    MyTimerJob myTJ = new MyTimerJob("contoso-job-add-mobile-adapter", webApp, null, SPJobLockType.None);
    

    Notez les observations suivantes relatives au code :

    • Le premier paramètre du constructeur de MyTimerJob est le nom interne du travail. Par convention, les noms internes des travaux sont en minuscules, comportent un trait d’union et commencent par le mot « job ». Pensez à ajouter le nom de votre entreprise au début du nom interne du travail, comme dans l’exemple.

    • Le deuxième paramètre spécifie l’application Web à laquelle le travail doit s’appliquer.

    • Le troisième paramètre peut être utilisé pour spécifier un serveur particulier sur lequel le travail doit s’exécuter. Le paramètre a la valeur null quand le travail doit s’exécuter sur tous les serveurs Web frontaux.

    • Le quatrième paramètre détermine si le travail s’exécute sur tous les serveurs Web frontaux. La transmission de SPJobLockType.None garantit qu’il s’exécute sur tous les serveurs sur lesquels le service application Web Microsoft SharePoint Foundation s’exécute. En revanche, la transmission de SPJobLockType.Job garantit qu’il ne s’exécute que sur le premier serveur disponible sur lequel le service application Web Microsoft SharePoint Foundation s’exécute (Il existe une troisième valeur possible. Pour plus d’informations, voir SPJobDefinition, ainsi que les rubriques consacrées à ses constructeurs et aux autres membres.)

  12. Ajoutez le code suivant à la méthode Main :

    // Schedule the job.
    myTJ.Schedule = new SPOneTimeSchedule(DateTime.Now.AddSeconds(30.0));
    

    SPOneTimeSchedule est l’une des nombreuses classes qui dérivent de la classe SPSchedule et qui peuvent être utilisées comme valeur de la propriété Schedule. Vous pouvez définir le travail pour qu’il s’exécute immédiatement en passant Now au constructeur. Cependant, il peut être instructif d’ajouter quelques instants, 30 secondes dans le cas présent, dans la phase de développement, car vous avez ainsi le loisir de voir le travail apparaître dans les définitions de travaux et les listes de travaux planifiés de l’application Administration centrale. Une fois le travail terminé, il s’affiche dans la liste de l’historique des travaux. Un travail périodique demeure indéfiniment sur la liste des définitions de travaux, mais un travail unique – à savoir, un travail avec un objet SPOneTimeSchedule comme valeur de sa propriété Schedule – existe (et, de ce fait, figure sur la liste des définitions des travaux) entre le moment où il est créé et celui où il s’exécute, soit, dans cet exemple, 30 secondes. Il est automatiquement supprimé après son exécution.

  13. Ajoutez le code suivant à la méthode Main :

    // Save the scheduled job instance to the configuration database.
    myTJ.Update();
    

Compilation du code

  1. Générez le projet dansVisual Studio.

  2. Exécutez le fichier exécutable sur un serveur de la batterie dans le contexte utilisateur d’un administrateur de batterie.

    Le travail apparaît sur les listes de définition des travaux et de travaux planifiés dans l’application Administration centrale jusqu’à ce que sa programmation soit exécutée. Dans l’exemple présent, la planification est de 30 secondes. À l’heure prévue, le travail s’exécute sur tous les serveurs. Il apparaît ensuite dans la liste de l’historique des travaux de l’application Administration centrale, puis disparaît de la liste des travaux planifiés. Comme il s’agit d’un travail unique, il disparaît aussi de la liste des définitions des travaux une fois qu’il s’est terminé avec succès.

  3. Vérifiez que le travail a été exécuté sur tous les serveurs. Dans l’exemple, vérifiez à cette fin que l’élément controlAdapter et ses deux attributs ont été ajoutés au fichier compat.browser situé dans le dossier C:\Inetpub\wwwroot\wss\VirtualDirectories\numéro_port\App_Browsers, où numéro_port est le numéro de port de l’application Web, sur chaque serveur.