Download.microsoft.com



Coach Sharepoint 2007< Atelier 4 />Créer votre Feature avec code behind pour SharePointSommaire TOC \o "1-3" \h \z 1Introduction PAGEREF _Toc208915387 \h 31.1Contexte fonctionnel PAGEREF _Toc208915388 \h 31.2Contexte technique PAGEREF _Toc208915389 \h 42Introduction et découverte des Features Receiver PAGEREF _Toc208915390 \h 62.1Présentation simplifiée: PAGEREF _Toc208915391 \h 62.2Référencement et définition PAGEREF _Toc208915392 \h 72.2.1La classe SPFeatureReceiver PAGEREF _Toc208915393 \h 72.2.2Référencement au Manifest PAGEREF _Toc208915394 \h 82.3Le code de base PAGEREF _Toc208915395 \h 113Introduction à l’API SharePoint PAGEREF _Toc208915396 \h 133.1La hiérarchie logique PAGEREF _Toc208915397 \h 133.2Classes et Namespaces PAGEREF _Toc208915398 \h 143.2.1Principaux Namespaces PAGEREF _Toc208915399 \h 153.2.2Les classes principales PAGEREF _Toc208915400 \h 163.2.3Gestion du contexte SharePoint PAGEREF _Toc208915401 \h 173.3Quelques samples PAGEREF _Toc208915402 \h 173.3.1Edition de propriétés d’un site PAGEREF _Toc208915403 \h 173.3.2Création de sous site PAGEREF _Toc208915404 \h 183.3.3Parcours des sous sites PAGEREF _Toc208915405 \h 183.3.1Requête sur un jeu de données de liste PAGEREF _Toc208915406 \h 193.4Gestion de la mémoire PAGEREF _Toc208915407 \h 204Conception d’une solution de développement Visual Studio pour des Feature Receivers: PAGEREF _Toc208915408 \h 234.1Préparation et configuration de l’outil PAGEREF _Toc208915409 \h 244.2Création du projet PAGEREF _Toc208915410 \h 244.3Création du corps d’une Feature PAGEREF _Toc208915411 \h 254.1Intégration du code métier PAGEREF _Toc208915412 \h 264.2Utilisation du contexte SharePoint PAGEREF _Toc208915413 \h 284.3Référencement du Feature Receiver PAGEREF _Toc208915414 \h 294.3.1Problématique du référencement et du déploiement PAGEREF _Toc208915415 \h 294.3.2Référer votre classe dans la Feature PAGEREF _Toc208915416 \h 304.1Batchs de déploiement d’une Feature PAGEREF _Toc208915417 \h 334.2Test et développement?: comment gagner du temps?? PAGEREF _Toc208915418 \h 344.3Développement?: quelques exemple de code PAGEREF _Toc208915419 \h 364.3.1Gestion de la navigation et des WebParts PAGEREF _Toc208915420 \h 364.3.2Ajout d’onglet de navigation PAGEREF _Toc208915421 \h 374.3.3Gestion des WebPart PAGEREF _Toc208915422 \h 394.4Ajout d’action personnalisé ??Custom Action?? PAGEREF _Toc208915423 \h 414.5Changement de Master Page PAGEREF _Toc208915424 \h 454.6Suppression des fichiers ajoutés PAGEREF _Toc208915425 \h 484.6.1Itération du contenu d’un liste PAGEREF _Toc208915426 \h 504.6.2Suppression par les fichiers PAGEREF _Toc208915427 \h 515Pour aller plus loin… PAGEREF _Toc208915428 \h 536Rendez-vous dans le prochain atelier… PAGEREF _Toc208915429 \h 55IntroductionCet atelier s’inscrit dans le cadre du tutorial de découverte du développement avec la technologie SharePoint 2007. L’objectif est la réalisation d’un modèle de site entièrement personnalisé avec la méthodologie expliquée pas à pas.Les exercices de l’atelier N°4 s’approchent désormais plus du monde des API SharePoint en les introduisant via le cycle de vie des Features inhérent à SharePoint 2007. Si les Features introduisent la notion de composant dans le développement SharePoint, elles sont aussi limitées aux possibilités fonctionnelles qu’offre le schéma CAML. Il est cependant possible de les étendre en s’appuyant sur les API de développement et les événements spécifiques aux Features.Ce chapitre permettra ainsi de faire la transition entre le monde déclaratif XML de SharePoint et celui du tout API tout en servant d’introduction aux bonnes pratiques de code dans le monde SharePoint. Contexte fonctionnelRappel du contexte fonctionnel du Tutorial de découverte de la technologie SharePoint 2007L’objectif du tutorial est de construire pas à pas un site personnalisé SharePoint incluant les grands axes de développement SharePoint tel que Création d’un modèle de site avec son design et sa charte graphiqueAjout de fonctionnalités déclaratives par les ??Features??.Ajout de fonctionnalités associées avec des événements de code .NetComposants WebPartSon Packaging et Déploiement completsContexte fonctionnel de l’atelier 4 dans le cadre du TutorialL’objectif est de découvrir la conception et la réalisation de Features avec événements de code pour des sites SharePoint.Les Features sont vraiment une des clés du fonctionnement propre de SharePoint 2007. Qu’il s’agisse de déployer les éléments de base ou de mettre en place la structure d’un projet, elles sont simplement incontournables.Leur cycle de vie propre, installation / activation / désactivation / désinstallation associé aux scénarii de regroupement et de ??stapling?? permettent bien des solutions. Mais ce n’est pas une fin en soi.Dans le framework SharePoint, vous pouvez aussi, intégrer vos propres actions de code dans le cycle de vie des Features simplement en les rattachant aux divers événements, précédemment citésSi les premiers tutoriels avaient permis de couvrir une bonne partie de l’aspect déclaratif du CAML, les événements de Feature avec Code nous font accéder à un autre niveau de personnalisation de la plateforme.En effet, il n’y a pas vraiment de limites aux possibilités du modèle objet SharePoint. L’API couvre potentiellement toute la plateforme SharePoint. Les événements de code les utilisent directement dans le cycle de vie de SharePoint?; et permet donc d’interagir au plus prêt du c?ur même du système de déploiement.Soit mixer les avantages communs des Features et du modèle objet?: une approche composant entièrement personnalisée.Contexte techniqueLe mode événementiel des Features n’est pas aussi complexe que l’on pourrait croire. Il nécessite 2 étapes?:Implémenter la classe abstraite SPFeatureReceiver et ses 4 méthodes de basesRéférencer le type et l’assemblée dans le manifest du FeatureIl est donc très aisé d’étendre ses Features et leur ajouter tout comportement métier nécessaire. D’ailleurs, on peut distinguer 3 scénarii de bases?:Une Feature étendue?:Il s’agit surtout d’ajouter une action visant à finaliser ou compléter le code déclaratif.Exemple?: utiliser un MODULE en CAML pour une nouvelle Master Page puis du code pour l’appliquer au site en cours.Une Feature applicative :Elle ne contient aucun élément de CAML, elle n’utilise que le système de code événementiel pour profiter du cycle de vie et introduire un comportement métier spécifique.Exemple?: créer et initialiser des groupes de sécurité dans un site SharePoint.Une Feature de déploiementCas particulier ou l’objectif est de profiter du Stapling de Feature sur un identifiant de site pour pouvoir déployer une action métier. Le but est cibler une mise à jour d’un modèle ou un suivi de génération.Exemple?: suivre la création de nouveau site en inscrivant dans une base de données, toute création de sous-site.Les API SharePoint combinées au framework .Net offre un panel de solution bien plus large, leur utilisation au c?ur même de la plateforme SharePoint par l’intermédiaire des événements de Features est définitivement un des principaux outils du développeur.Mais les API SharePoint imposent aussi une approche spécifique du fait même des spécificités de la plateforme qu’il s’agisse du moteur et de sa gestion mémoire. De ce fait, ce tutoriel fera une introduction aux diverses bonnes pratiques du développement et de la hiérarchie objet de SharePoint 2007.L’objectif de ce tutoriel est de vous permettre de bien comprendre l’utilisation des API et ceux dans le cas de Feature. Bien sur, nous restons dans le fil rouge initié par les tutoriels précédent?: étendre un site SharePoint. Ainsi, les exemples seront basés sur des Features déclaratives déjà vu mais complétées fonctionnellement (ajout de comportement, mise à jour, …).Bien entendu, les Best Practices, astuces de développements et quelques retours d’expérience seront au c?ur même de ces exemples.A la fin, vous saurez comment :Créer votre propre Feature ReceiverMonter une solution de développement SharePoint pour vous faciliter sa conceptionTravailler avec divers objets SharePoint comme les listes, les menus Allez plus loin dans la découverte dans la personnalisation SharePointSoit en pratique?:Introduction et découverte des Features ReceiverPrésentation simplifiéeRéférencement et définitionCode de baseIntroduction au API SharePointLa hiérarchie logiqueLes classes de basesGestion de la mémoireConception d’une solution de développement Visual Studio :Préparation et configuration de l’outilCréation du projet et des scripts de travailCréation d’une Feature Receiver SimpleDivers exemple clés en main Personnalisation de la navigation et des WebPartsMenu dynamiqueSuppression de fichierMaster Page et son application Cet atelier se base sur l’utilisation de la technologie SharePoint 2007 via son offre de base Windows SharePoint Services V3?(WSS). La lecture des tutoriels du Coach 1 & 2 & 3 est un vrai plus pour une compréhension globale.? Note?:Introduction et découverte des Features ReceiverDans cet exercice, vous allez découvrir :La composition d’une Feature ReceiverLes différents concepts utilisés par le système des Features.Le r?le des différents fichiers et référencesObjectifL’objectif de ce chapitre est de vous permettre de mieux appréhender la déclaration et l’utilisation des événements de code ou Feature Receiver SharePoint et leur intégration au c?ur même de la plateforme. Vous pourrez ainsi, aisément créer vos propres Receiver et étendre vos Features.Contexte fonctionnelLes Features sont au c?ur du système de déploiement et de fonctionnement de SharePoint 2007 gr?ce à une modularité et un cycle de vie complet. Certes, une approche exclusivement basée sur le déclaratif (CAML) montre très vite ses limites d’utilisation?; mais l’utilisation des Features Receiver ouvre tout le potentiel du framework .Net et des API me les Features interviennent quasiment au plus bas niveau du système de génération, qu’elles soient définies dans un Site Definition ou activées par la suite ou via Stapling, les Feature Receiver vous permettent d’intégrer votre propre code métier à ce niveau sans rien modifier ou interférer avec la plateforme d’origine.Cependant, il s’agit désormais d’exploiter du ??vrai code?? soit des problématiques d’exécution, de compilation de gestion mémoire et de sécurité?: en résumé, le véritable domaine du développeurPrésentation simplifiée:Le principe de base des Feature Receivers est d’attacher une assemblée métier à une Feature. Le code contenu et compilé sera utilisé lors des 4 événements de base de la Feature soit?: installation activation désactivation désinstallationPour qu’une assemblée puisse être utilisée comme telle, elle doit respecter quelques règles de développement?:implémenter la classe abstraite SPFeatureReceiver être déployée dans le Global Assembly Cache Posséder un nom fort (Strong Name)Bien sur, un Feature Receiver n’existe pas sans une Feature la référen?ant. On utilise ainsi le nom fort de l’assemblée ainsi que le type de classe pour le déclarer dans le manifest XML de la FeatureComme vous le constater, la démarche est simple mais elle se doit d’être exacte et précise.La dernière remarque n’est pas qu’un simple avertissement ou un effet de style mais un point très important. Comme vous avez du le remarquer, SharePoint 2007 est tout autant un framework de développement qu’un pro logiciel de gestion de l’information (ECM). Tout utilisation de code via une assemblée tiers introduit la notion d’intégration à un existant, sous entendu de contrat d’utilisation et de compilation.En effet, le système SharePoint ne peut être recompilé et redéployé, vous ne pouvez qu’exploiter les interfaces de communication ou d’intégration prévues par la plateforme.Dés lors, vous devez vous attacher à bien respecter les prochaines étapes que nous allons parcourir dans ce tutoriel sinon, vous risquez simplement de ne pouvoir exploiter votre code métier. En intégration, l’application Maitre reste toujours la seule et unique référence. Notez cependant que SharePoint 2007 reste avant tout une application ?: aucune des règles que nous allons évoquer ne sera donc une totale nouveauté, elles ne seront que des utilisations souvent avancés du framework Microsoft. Rien de plus, rien de moins. Référencement et définitionLa classe SPFeatureReceiverCette classe abstraite permet de s’attacher aux événements de base du cycle de vie d’une Feature via 4 méthodes que vous devez surcharger?:FeatureActivated?: après activation de la Feature FeatureDeactivating?: lors de la désactivation de la Feature FeatureInstalled?: après installation de la Feature FeatureUninstalling?: lors de la désinstallation de la Feature Elle appartient au namespace Microsoft.SharePoint de la dll Microsoft.SharePoint.dll. Vous trouverez cette assemblée à ce chemin[Program Files]\Common Files\Microsoft Shared\web server extensions\12\ISAPI SPFeatureReceiver vous suffit donc de créer un projet de type assemblée (Assembly) sous Visual Studio et implémenter cette classe (sans oublier la référence à la Microsoft.SharePoint.dll)Exemple en C#using System;using System.Collections.Generic;using System.Text;using Microsoft.SharePoint;namespace DemoReceiver{ public class FeatureEventHandler : SPFeatureReceiver { public override void FeatureActivated(SPFeatureReceiverProperties properties) { } public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { } public override void FeatureInstalled(SPFeatureReceiverProperties properties) { } public override void FeatureUninstalling(SPFeatureReceiverProperties properties) { } }}Exemple en Imports SystemImports System.Collections.GenericImports System.TextImports Microsoft.SharePointNamespace DemoReceiver Public Class FeatureEventHandler Inherits SPFeatureReceiver Public Overloads Overrides Sub FeatureActivated(ByVal properties As SPFeatureReceiverProperties) End Sub Public Overloads Overrides Sub FeatureDeactivating(ByVal properties As SPFeatureReceiverProperties) End Sub Public Overloads Overrides Sub FeatureInstalled(ByVal properties As SPFeatureReceiverProperties) End Sub Public Overloads Overrides Sub FeatureUninstalling(ByVal properties As SPFeatureReceiverProperties) End Sub End ClassEnd NamespaceRéférencement au ManifestLa création de la classe n’est pas vraiment un défi en soi. Cependant pour pouvoir la référencer dans le manifest de votre Feature, vous devez respecter 2 consignes importantesDonner un nom fort à votre DLLLa placer dans le GAC de votre serveurIl faut donc dans un premier temps pouvoir signer votre assembléeSigner votre dllLes 2 notions sont intimement liées?: seuls des DLLs signées peuvent être déployées dans le GACGACChaque ordinateur sous Windows exécutant le framework .Net possède un cache de code à l'échelle de l'ordinateur appelé Global Assembly Cache. Le Global Assembly Cache stocke les assemblées spécialement destinées à être partagées entre plusieurs applications sur l'ordinateur. (VS.80).aspxNom fort d’une assembléeUn nom fort est constitué de l'identité de l'assemblée (son simple nom textuel, son numéro de version et des informations de culture, le cas échéant) ainsi que d'une clé publique et d'une signature numérique. Il est généré à partir d'un fichier d'assemblée et à l'aide de la clé privée correspondante lors de la compilation(VS.80).aspxLes dernières versions de Visual Studio possèdent un onglet de projet réservé à la signature de votre assemblée. Vous pouvez ainsi créer ou pointer directement une clé de signature.Les clés de signature sont réutilisables, vous pouvez très bien définir une seule clé pour plusieurs composants de votre projet en la référen?ant à chaque fois. Prenez bien soin de la préserver en l’incluant par exemple dans Visual Sourcesafe car vous ne pouvez régénérer une clé?: elle est unique et personnelUne fois votre assemblée compilée, il faut ensuite récupérer son nom fort soit une clé de son nom, son numéro de version, des informations de culture et du code alphanumérique de sa clé. Il existe plusieurs méthodes pour le faire?:Extraire la clé publique par sn -T [assembly]".(Méthode assez spartiate)Extraire le nom fort depuis Reflector(Il suffit de glisser déplacer votre dll dans l’interface et récupérer le nom fort comme indiqué)Reflector est certainement l’un des outils indispensables de tout développeur .Net (et donc SharePoint). C’est un programme gratuit permettant de décompiler des exécutable ou dll .net. Vous pouvez télécharger ce programme à cette adresse : notre tutoriel, nous utiliserons un projet SharePointFeature_Advanced. Après compilation, nous obtenons le nom fort?:SharePointFeature_Advanced, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e727ec7a42e5a6a9Référencer la dll dans une FeatureMaintenant que nous avons obtenu le nom fort, nous pouvons la référencer dans notre manifest XML. Nous ne reviendrons pas sur le détail de la conception/création d’une Feature puisque le coach N°3 le couvre largement. Sa lecture est vraiment un pré requis.Pour cela, il nous suffit d’utiliser 2 nouveaux attributs dans le manifest de la Feature soit le fichier Feature.xmlReceiverAssembly?: indique le nom fort de l’assembléeReceiverClass?: indique le type complet de la classe (namespace + nom de classe)Soit Manifest Feature.xml<?xml version="1.0" encoding="utf-8"?><Feature Id="cbefa107-97ef-4b92-be00-a89d6ab22dad" Title="Coach – Advanced " Description="Feature ..." Version="12.0.0.0" Hidden="FALSE" Scope="Web" DefaultResourceFile="core" ImageUrl="Wygwam/StramitFeature.gif" ReceiverAssembly="SharePointFeature_Advanced, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e727ec7a42e5a6a9" ReceiverClass="SharePointFeature_Advanced.AutoDelete_Receiver" xmlns=""><ElementManifests><ElementManifest Location="elements.xml"/></ElementManifests></Feature>Le code de baseLes Features Receivers permettent d’accrocher un code métier au cycle de vie d’une Feature?; mais ils sont aussi liés au scope de celle-ci. En effet, le niveau d’activation de la Feature influe aussi sur le contexte de son événement rattaché. Une Feature de niveau Web travaille dans le contexte Web et ainsi de suite pour les niveaux Site Collection, Web Application ou Farm.Il faut tenir compte de ce contexte pour justement pouvoir initialiser son code lors du développement et donc attaquer les bons objets. Si vous codez un Receiver pour une Feature de niveau collection de site, votre code doit cibler particulièrement les objets de la collection de site, soit la classe SPSite.Le framework SharePoint gère bien cette exploitation de contexte via les paramètres et les propriétés inhérentes au SPFeaturereceiver.Prenons un exemple simple, une Feature de niveau Web. L’objectif premier est de pourvoir accéder à l’objet représentant le site Web soit la classe SPWeb Manifest Feature.xmlusing System;using Microsoft.SharePoint;namespace SharePointFeature_Advanced{ class Custom_Receiver : SPFeatureReceiver { public override void FeatureActivated(SPFeatureReceiverProperties properties) { SPWeb web = properties.Feature.Parent as SPWeb … } }}Il suffit simplement d’utiliser le paramètre de type SPFeatureReceiverProperties qui reprend toutes les propriétés de votre Feature. En pratique, exploiter la variable ??properties?? SPFeatureReceiverProperties pour les différents niveaux de FeatureScopeExempleWebSPWeb web = properties.Feature.Parent as SPWebSiteSPSite site = properties.Feature.Parent as SPSiteWeb ApplicationSPWebApplication webapp = properties.Feature.Parent as SPWebApplicationFarmSPFarm farm = properties.Feature.Parent as SPFarmDésormais, vous connaissez les basiques pour arriver à développer vos premiers Feature Receivers. Avant de continuer ce tutoriel par une revue de la méthodologie et bien sur l’analyse fine de plusieurs exemples documentés de code, nous continuerons ce tutoriel avec une introduction aux divers objets de l’API SharePoint.Objets Maitres, gestion de la mémoire, parcours des méthodes principales, et autre vous permettront de faire vos premiers essais dans la conception de vos Feature Receivers et tout autre développement bien sur.? Note?:Introduction à l’API SharePointDans ce chapitre, vous allez découvrir :Les interactions entre les différents objets de l’APILes principaux objets du framework SharePointLa gestion de la mémoire avec SharePointObjectifL’objectif de ce chapitre est de vous faire découvrir l’API SharePoint et sa relation avec l’architecture logique et métier du produit lui-même. Il ne s’agit pas de présenter l’ensemble des classes et autres propriétés que vous pouvez trouvez dans le MSDN mais bien de comprendre comment vous pouvez interagir avec SharePoint via ses principaux objets Contexte fonctionnelIl existe différents moyens d’interaction avec SharePoint 2007?: Ligne de commande, interface, web Service et Modèle objet. Clairement, le travail du développeur se situe au niveau de l’API et de ses diverses classes de base.Tout comme SharePoint, son API est extrêmement riche en possibilités. Toutes les fonctionnalités du produit sont couvertes par son modèles objet, qu’il s’agisse? de la génération de liste, de site, de l’administration d’un site particulier, de ses sécurités jusqu'à l’administration des bases de contenu Connaitre le panorama complet des objets SharePoint peut demander du temps, mais si vous pouvez relier les classes de base avec l’architecture du produit, vous pourrez accéder plus facilement à des éléments plus concrets et surtout fonctionnels. Soit dépasser le cadre strict de la documentation techniqueLa hiérarchie logiqueSharePoint 2007 possède une API très riche mais heureusement, tout aussi simple d’utilisation.2 raisons à vrai dire?:Chaque objet métier possède ses méthodes propres et est fortement typé Il n’y a donc pas de risque de travailler avec des méthodes riches renvoyant des objets ??variant??. Toutes les méthodes ou propriétés de chaque classe sont typés et, en plus, spécifique au contexte courant. Prenons l’exemple d’une liste (objet SPList), sa collection d’élément est de type SPListIem avec ses propres méthodes de sélection et d’indexation.L’auto complétion de Visual Studio combinée à son explorateur de classe facilite le parcours de la hiérarchie objet SharePoint, ne la négligez pas?!La hiérarchie des objets dans SharePoint est clairement liée à son architecture logique.Cette notion d’architecture logique avait été parcourue lors du premier coach SharePoint. A vrai dire, s’il existe une notion fondamentale dans la technologie SharePoint, c’est bien celle-ci.A chaque élément de la hiérarchie, correspond une classe de l’API correspondante, ainsi que les objets enfants. Soit le schéma suivantLa règle de nommage des classes est très pratique?: ??SP?? en Préfix + Nom de l’élémentAinsi, vous pouvez déjà identifier vos classes de base de votre code avant même de commencer votre développement.Exemple?:Liste SPListSite Web SPWebChamps de liste SPField…Il est très important de bien comprendre et connaitre le schéma précédent. Gardez toujours ce schéma à l’esprit quand vous faites votre conception technique. A la limite et dans un premier temps, il serait bien de l’imprimer le et de le conserver précieusement.Classes et NamespacesLe modèle objet de SharePoint repose sur plus d’une dizaine d’assemblées. La plupart sont spécifiques aux divers services de MOSS comme le publishing, la recherche, forms service, …En ce qui concerne la base même de SharePoint 2007, soit les listes, les sites, les Features et l’ensemble du modèle de génération, elle s’appuie sur le namespace Microsoft.SharePoint de l’assemblée?: Microsoft.SharePoint.dllPrincipaux Namespaces1945882490973098165102870Il existe actuellement 35 namespaces dans WSS V3 vous permettant d’accéder à toutes les fonctionnalités sous jacentes de SharePoint 2007 et étende largement vos possibilités de développements. Pour donner un point de comparaison, WSS V2 ne comprenait que 12 namespaces.Les namespaces les plus utilisés restent cependant?:Microsoft.SharePointles objets de bases sont iciMicrosoft.SharePoint.WebControls Il comprend les différents contr?les Web utilisés dans les sites SharePoint comme le SPGridView, la grille étendue utilisée dans le rendu de la liste par exempleMicrosoft.SharePoint.Utilities Véritable boite à outils, c’est un ensemble de classe utilitaire incontournable?: De la gestion des notions de conversion de format (SPencode) à l’envoie de mail par exemple. N’hésitez pas à parcourir toutes ses micros fonctions souvent très utilesMicrosoft.SharePoint.Utilities Accès direct à l’administration de SharePoint. Très utilisé avec une élévation de privilèges pour déléguer la configuration par exempleLes autres namespaces sont à utiliser en fonction de vos besoins, chacun étant spécifique à un r?le ou service spécifique de SharePoint comme la navigation, les pages à WebPart, la recherche ou les workflowsLe namespace SharePoint est vraiment riche mais les sous namespaces sont classés par métier de base, il n’y a pas de risque de ??mélanger?? les classes.Soit en pratique?:Microsoft.SharePoint.NavigationMicrosoft.SharePoint.WebPartPagesMicrosoft.SharePoint.WorkflowMicrosoft.SharePoint.Search.QueryAttention de ne pas trop référencer automatiquement de namespace, sinon l’auto complétion ne sera plus vraiment utile. Les classes principalesLe développement SharePoint a un focus particulier sur la vie propre du site SharePoint. Il ne s’agit pas de renier la partie génération ou administration mais le propre de la technologie SharePoint reste de créer des sites à la demande. Il est donc légitime, que le développement soit centré sur les sites SharePoint Si on se référence à l’architecture logique, il s’agit de se concentrer sur les notions de collection de site et de site Web. Pour rappel, un site SharePoint ne peut exister sans son conteneur, soit la collection de site, c’est un couple indissociable. Il faut toujours considérer le site Web SharePoint et sa collection ainsi que sa position dans la hiérarchie?: soit un sous site ou un site de racineEn terme de modèle objet, il faut référencer les classes SPSite (Site Collection) et SPWeb (site Web).Par extension, les classes enfants comme SPList (les listes), SPFields (champs d’une liste), SPListItem (éléments d’une liste) sont souvent les prochaines classes que vous utiliserez dans votre code métier.Gestion du contexte SharePointSharePoint 2007 est une usine à site, il est donc difficile de planifier le nombre de site et leur identité à l’avance. Grace à cette notion de contexte SharePoint, vous pouvez rendre vos développements génériques et les rendre adaptatifs, tout simplement, en exploitant les données du contexte.Le travail en devient que plus simple car complètement indépendant de la plateforme ou de sa configuration, seul le contexte fait référence.Utilisation du contexte depuis une page SPWeb web = SPContext.Current.Web SPSite site = SPContext.Current.SiteBien sur, il est possible d’initialiser les 2 classes de site via un identifiant direct. On utilise ce scénario lorsque le site en question n’est pas celui du contexte en cours, ou tout simplement dans un développement non ?: Smart Client, Winform, … Il n’existe pas beaucoup de constructeur dans les classes de SharePoint. Ainsi, il n’est pas possible d’instancier en direct une liste ou un site Web. Il faut obligatoirement travailler au niveau de la collection de site puis du web pour arriver à une liste car seul le SPSite, à ce niveau d’architecture logique possède un constructeur.Utilisation hors d’un contexte //utilisation de l'adresse compléte SPSite site = new SPSite("") //récupération du SPWeb par l’adresse SPWeb web = site.OpenWeb() //utilisation d'un GUID SPWeb web = Site.AllWebs[SiteGUID] Une fois que vous avez accès à l’objet SPWeb, le site SharePoint entier est désormais éditable. La classe SPWeb fournit toutes les propriétés pour travailler sur ses paramètres ainsi que ces composants subalternes tels que les listes, les pages, les contenus, … SPsite.openWeb() possède plusieurs surcharges très pratiques exemplesIl serait compliqué de couvrir tout l’éventail de l’API SharePoint surtout dans une introduction. Le prochain chapitre va justement détaillé du code métier. Cependant, pour faciliter la transition, nous allons parcourir quelques extraits de code à la base de bien des personnalisations SharePoint.Edition de propriétés d’un siteGestion des propriétés d’un site // Editer les propriétés du site web.Title = "Site de DEMO";web.Description = "Demo demo demo";// Permettre la syndication RSSweb.SyndicationEnabled = true;// Edit site navigation settingsweb.QuickLaunchEnabled = true;web.TreeViewEnabled = false;// valider/commit les changementsweb.Update();Attention de toujours contr?ler si un objet supérieur dans SharePoint ne demande pas une validation par la méthode ??update??Création de sous siteAjout de sous site// Editer les propriétés du site web.Add("Alias", "Nom du site", "Description…" ,1036, "STS#0",true,false);STS#0 correspond à la clé de configuration du modèle de site utilisé. Cette notion a été vue lors du coach sur les Site Definition. Vous pouvez les retrouvez en regardant les données des fichiers WebTemp*.xmlParcours des sous sites Parcours récursif // Ensemble des sous sites existants foreach (SPWeb subWeb in parentWeb.Webs) { ... } // Ensemble des sous sites accessibles pour l’utilisateur en cours SPWebCollection SubWebcol = parentWeb.GetSubwebsForCurrentUser(); foreach (SPWeb subSite in SubWebcol) { ... }Attention à la gestion des droits, certaines propriétés comme SPSite.AllWebs ne fonctionnent que pour un r?le administrateurRequête sur un jeu de données de liste Il existe plusieurs manières d’accéder aux données d’une liste. Avant tout, il faut instancier la liste en question via son SPWeb et son SPSite.Une fois, l’instance de SPList, vous pouvez travailler soit en parcourant la collection des items (SPListItem), soit celle d’une des vues de la liste (SPView).Dans le cas, ou vous recherchez un jeu de données bien précis, en utilisant des filtres par exemple, vous devez utiliser une requête, non pas en SQL mais en ce si charmant langage qu’est le CAML.Il ne s’agit pas d’utiliser tout le schéma CAML mais seulement la sous partie utilisée pour créer la condition de filtre des vues?: le CAML QueryQuery schema à cette requête, vous pouvez utilisez l’objet SPQuery qui servira de moteur de filtre à votre listeRequête via CAML SPSite site = new SPSite(siteUrl); SPWeb web = site.OpenWeb(); SPList listContact = web.Lists["Contacts”]; SPQuery query = new SPQuery(); string caml = "<Query><Where><Eq><FieldRef Name='LinkTitle'/><Value Type='Text'>Coach</Value></Eq></Where></Query>"; query.Query = caml; SPListItemCollection listItemContact = listContact.GetItems(query); String txt; foreach (SPListItem i in listItemContact) { txt = i["LinkTitle"].ToString() + " " + i["Company"].ToString()); }Le CAML Query est très proche d’un langage SQL mais décrit en XML. Son écriture étant assez subtile au début, il est bon de s’appuyer sur des projets communautaires pro CAML. Ainsi, en générant le c?ur des requêtes de base, vous pourrez concevoir plus facilement les v?tres. de la mémoireSharePoint a beau être qu’une application assez évoluée, sa charge en mémoire, ses nombreuses références et son provider de virtualisation impose une gestion fine de votre mémoire.Non pas que le ??Garbage Collector?? de .Net fait mal son travail, loin de la, mais la taille des objets SharePoint, leur interaction avec la couche COM impliquent de toujours les ouvrir au plus tard et les libérer au plus t?t.Certes, il s’agit d’un grand classique du développement .Net mais encore plus important dans le monde SharePoint.Il est très rare de constater quelques ralentissements lors du développement mais une fois votre code en production avec 200 utilisateurs et plus, la gestion de la libération de vos objets SharePoint sera votre seul gage de performance?!Le bout de code ci-dessus doit clairement faire partie de vos Best Practices des le début de votre développement.Gestion de la mémoire sous SharePoint//Hors contexte SharePointusing(SPSite oSPsite = new SPSite("")){ using(SPWeb oSPWeb = oSPSite.OpenWeb()) { str = oSPWeb.Title; str = oSPWeb.Url; }}//Dans le contexte SharePointSPSite oSPSite = SPControl.GetContextSite(..);using(SPWeb oSPWeb = oSPsite.OpenWeb()){ ... additional processing ... } Lecture indispensable Best Practices: Using Disposable Windows SharePoint Services Objects information, voici quelques données de test en mémoire où la gestion de la libération mémoire n’est pas faiteUsersBest CaseWorst Case10100 MB200 MB50500 MB1000 MB1001000 MB2000 MB2502500 MB5000 MBLes sympt?mes sur une ferme de production SharePoint sont multiples mais les plus visibles sont?:Un recyclage régulier de l’application pool !!! De piètres performances sous forte charge De nombreux Time Outs Il existe aussi un autre phénomène bien dangereux sous SharePoint 2007 qu’il faut absolument savoir maitriser?: la pression mémoire.La plupart des objets maitres sous SharePoint possèdent quelques références à des objets COM. Objets très difficiles à libérer en mémoire si jamais ils s’accumulent dans la pile de .Net. Le seul moyen est d’être sur d’avoir procéder à un .Dispose à la fin d’utilisation de vos objetsCertes, c’est exactement ce que fait le ??using?? dans la portée de son code dans le Best Practice précédent. Cependant, le risque est de bien gérer aussi la libération de sous objets qui eux feraient aussi des références implicites. Prenons par exemple le cas d’une boucle itérant dans les sous site d’une racine de collection. Certes, le Using, assure que vous libérez la mémoire de l’objet de racine, mais il faut aussi s’assurer de libérer toutes les références des sous sites?!Gestion des références implicites//Référence de sous siteSPWeb oSPWeb = SPContext.Web;foreach(SPWeb oSubWeb in oSPWeb.GetSubWebsForCurrentUser())){ // .. Add subweb information for navigation .. oSubWeb.Dispose();}//Référence de site en créationusing (SPWeb web = siteCollection.AllWebs.Add("site-relative URL")){} // SPWeb object web.Dispose() automatically called//Référence implicite vers les objets fils ou parentusing (SPSite siteCollection = new SPSite("")){ SPUser ownerUser = siteCollection.Owner; siteCollection.RootWeb.Dispose();} Lecture indispensable Roger Lamb : SharePoint 2007 and WSS 3.0 Dispose Patterns by Example Go?ner : Dealing with Memory Pressure problems in MOSS/WSS fran?ais par votre coach?: Gestion du Dispose : Attention au Memory Pressure sous SharePoint (et donc comment faire mieux)ésormais, vous connaissez un peu mieux les arcanes de l’API SharePoint. Il ne vous reste plus qu’à pratiquer, soit coder, tester et déployer.Et pourquoi pas, dans le cadre de Feature Receiver, le c?ur de ce tutoriel.? Note?:Conception d’une solution de développement Visual Studio pour des Feature Receivers:Dans cet exercice, vous allez apprendre à?:Créer votre propre Feature Receiver?;Coder et tester votre code métierImplémenter?:Des menus de navigationsUne suppression des contenus d’une listeUne mise à jour récursive des Master PagesObjectifL’objectif de cet exercice est de créer des Feature Receivers de site SharePoint. Ce tutoriel complétera les exemples couverts dans le tutoriel des Features tout en déclaratif afin de les finaliserContexte fonctionnelLe dernier Coach sur les Features déclaratives va être mis en pratique dans ce tutoriel. Les derniers exemples couverts montrer les diverses possibilités du CAML. Grace aux Features Receivers, nous allons pouvoir aller encore plus loin en rajoutant un comportement métier.Nous sommes bien dans les bornes d’un projet de personnalisation SharePoint où nous introduisons du code métier pour compléter notre code déclaratif. Le but étant bien d’étendre la plateforme native une fois que 80% du besoin a été couvert via la modélisation CAML. Il faut toujours privilégier le potentiel de la plateforme SharePoint pour mieux l’enrichir ensuite via le développement .Net. Sinon, vous risquez de tomber dans le piège du tout développement, et donc de faire une simple application et non SharePoint. Dans cette exemple, nous reprendrons donc les exercices sur les Features Déclaratives mais en introduisant une bonne dose de dynamisme Création de hiérarchieAjout de Master PageCréation de pages à WebPartCréation de menuCréation de listeComme par exemple?: Appliquer une Master Page au site une fois celle-ci ajoutée dans la collection ou encore modifier le Site Action avec une menu contextuel. Afin de respecter au mieux une démarche projet, nous nous placerons en situation en implémentant le tout dans une solution Visual Studio en détaillant la méthodologie utilisée pour coder, tester et déployer.Pour mieux comprendre le fonctionnement intrinsèque de la plateforme, ce chapitre et l’ensemble de ces exercices ne seront pas basés sur les extensions SharePoint pour Visual Studio. Ces extensions créent une abstraction de la plateforme pour le développeur afin de lui faciliter le travail. L’objectif du Coach SharePoint étant de vous aider à découvrir et comprendre le fonctionnement de cette technologie, nous travaillerons au plus proche de celle-ci. L’utilisation des extensions pour Visual Studio ainsi que des projets communautaires comme le WSPBuilder ou STSDev sont un vrai ??plus?? pour les développeurs. Nous ne pouvons que vous encourager à les découvrir une fois ces exercices réalisés.Préparation et configuration de l’outilA vrai dire, il n’y a pas de spécificité propre si ce n’est d’appliquer toutes les anciennes remarques du coach 1,2 et 3Soit en résumé rapide?:Respecter une structure de dossier similaire au répertoire 12 de SharePointPrivilégier le développement depuis un serveur SharePoint avec Visual Studio (Virtuel machine par exemple)Bien paramétrer Visual StudioDéfinition du schéma WSS.Xsd dans l’IntelliSenseRéférence à la Microsoft.SharePoint.dllToujours travailler à partir d’un nouveau site voir d’une nouvelle collection de site pour éviter des effets collatéraux entres les développementsCréation du projet La première phase de tout projet SharePoint est de pouvoir créer un environnement de développement dédié et favorable à ses spécificités. Comme nous l’avons vu dans les premiers chapitres, nous utiliserons encore et toujours une arborescence similaire au fameux répertoire 12 contenant l’ensemble des fichiers systèmes mais dans le projet Visual Studio.Déroulement de l’exercice :Ouvrir Visual Studio et créer un projet de développement de type Class Library.Nous allons créer un modèle de site que nous appellerons ??SharePointFeature_Advanced?Reproduire l’arborescence du répertoire 12 nécessaire à notre projet via l’ajout de dossier dans l’explorateur Visual Studio Il faut créer l’arborescence suivante12 (le c?ur système de SharePoint)Ressources (pour gérer les fichiers de traduction Rex)TEMPLATE (répertoire des modèles)IMAGES (stockage des images)FEATURES (Stockage des ??Features?)Batchs (scripts d’initialisation du projet)FeatureCode (pour classer nos divers fichiers de classes à compiler)Création du corps d’une FeatureComme notre projet est un Feature Receiver, il faut gérer en fait, 2 projets en même temps?:L’assemblée métierLa Feature en CAMLIl serait tout à fait normal de créer 2 projets séparés mais comme une Feature déclarative n’est qu’un assemblage de divers fichiers XML, nous pouvons très bien les associer dans le même notre projet utilise le modèle de librairie de classe, il peut très bien compilé sans soucis la DLL du Feature Receiver, il ne reste donc qu’à intégrer notre arborescence du 12 et les fichiers XML d’une Feature.A noter que ce principe de mélanger le XML CAML avec une compilation de classe sert aussi à la plupart des conceptions SharePoint qu’il s’agisse de WebPart, d’Event Receiver et/ou de Workflow. Ce n’est pas vraiment une surprise, comme nous avons vu dans le précédent tutoriel, quelque soit la problématique à gérer dans SharePoint 2007, il faudra forcement?:Une Feature (donc des fichiers XML)Les différents manifest XMLUne ou plusieurs DLLs métier (si nécessaire)Maintenant que le projet est créé, il faut l’initialiser, et donc reprendre les étapes d’une création d’une Feature déclarative?:Sous Dossier au nom de la Feature dans 12/TEMPLATE/FEATURESUn manifest Feature.xml avec un nouveau GUID en identifiantUn fichier Element.xml si besoinN’oubliez pas les fichiers de ressources pour la gestion multilingue?!!!69850116205Détail important?: du fait de la mixité du projet, vérifiez toujours que les fichiers à destination du 12 SharePoint ne soient pas compilables (Build Action?: None)C’est surtout le cas pour les fichiers RESX dans les répertoires de ressources des Features par exemple, ils n’ont pas besoin d’être compilés vu qu’ils seront déployés et utilisés par le moteur SharePoint automatiquementEvidemment, pour plus de précision sur la création d’un projet de Feature sous SharePoint 2007, la lecture du coach N°3 sur le sujet est plus que conseillé.Intégration du code métierPour obtenir un Feature Receiver, il suffit d’ajouter un fichier de classe à compiler qui doit d’implémenter la classes abstraite Microsoft.SharePoint.SPFeatureReceiverGestion des références implicitesusing System;using System.Collections.Generic;using System.Text;using Microsoft.SharePoint;namespace SharePointFeature_Advanced{ class Votre_Receiver : SPFeatureReceiver { public override void FeatureActivated(SPFeatureReceiverProperties properties) {… } public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { … } public override void FeatureInstalled(SPFeatureReceiverProperties properties) { } public override void FeatureUninstalling(SPFeatureReceiverProperties properties) { } }}La problématique n’est pas vraiment la création d’un classe ni sa compilation mais le respect des quelques spécificités que nous avons vu en introduction comme, par exemple, le nom fort, la signature et le GAC.Et donc, à la différence d’un simple projet de classe, il ne faut pas oublier de?:Référencer la Microsoft.SharePoint.dll Chemin de la DLL?:[Program Files]\Common Files\Microsoft Shared\web server extensions\12\ISAPISigner votre projet avec une clé (comme décris au paragraphe 2.2.2.1)En effet, pour pouvoir déclarer votre DLL dans le manifest de Feature et la déployer dans le GAC, vous devez donner à votre assemblée un nom fort via signature. Vous pouvez bien sur réutiliser une clé de signature ou en créer une nouvelle depuis l’interface de propriétés du projetDans notre tutoriel, nous allons travailler sur 4 Features Receivers différents, soit 4 Features CAML et donc 4 Classes Receiver. Afin de faciliter la compréhension, tout le code métier a été factorisé dans un classe ??Feature_Engine? qui sera utilisé en référence dans les autres classes implémentant SPFeatureReceiver. Pour éviter l’amalgame entre la classe métier et celle du Receiver, un dossier Feature_Code a été ajouté pour les classer. Il y a aussi une raison très pratique à cette séparation que nous verrons en détails par la suite.Utilisation du contexte SharePointUn développement sous SharePoint se doit d’être générique et surtout contextuel. Tout simplement pour pouvoir exploiter la notion de génération de site propre à cette plateforme.Dans le cas du framework Web, il est possible de récupérer le contexte SharePoint via la l’objet SPContext. Il est surtout utilisé lors de développement d’Application page, WebPart ou de Web Service.Mais en ce qui concerne les Feature Receiver, le contexte Web n’est pas accessible directement du fait du cycle de vie particulier des événements. Vous pouvez contourner ce problème via les paramètres du Feature ReceiverGestion du contexte? public class FeatureEventHandler : SPFeatureReceiver? {??? public override void FeatureActivated(SPFeatureReceiverProperties properties)??? {????? SPSite site = properties.Feature.Parent as SPSite;????? SPWeb web = site.OpenWeb();…??? }La classe SPFeatureReceiverProperties permet ainsi d’accéder à divers propriétés de la Feature à la base de l’appel du Receiver comme son titre, sa description ou même le flux complet du manifest de celle-ci. SPFeatureReceiverProperties fait, ces divers propriétés sont accessibles via les des classes représentant le manifest de la Feature (Definition As SPFeatureDefinition) ou l’instance de la Feature elle-même (Feature As SPFeature).“properties.Feature.Parent” fait justement référence à l’instance parent de la Feature, sous entendu, l’élément SharePoint où la Feature a été utilisée. Soit en pratique, l’instance du niveau du scope de la celle me une Feature ne possède que 4 scopes ou niveaux?: Farm / WebApplication / Site Collection / Web, vous devez typer cette propriété toujours selon le scope de votre FeatureAinsi, si vous travaillez sur une Feature de scope Web, vous pouvez récupérer le contexte d’exécution, donc interagir sur le site web avec ce simple appel?: Gestion du contexte pour un scope Web? public class FeatureEventHandler : SPFeatureReceiver? {??? public override void FeatureActivated(SPFeatureReceiverProperties properties)??? {?????SPWeb web = properties.Feature.Parent as SPWeb;…??? }Une fois que vous possédez une référence sur la classe SPWeb, vous avez accès à tout le site Web SharePoint en cours, de ces listes, à ses sécurités et tout son contenuRéférencement du Feature ReceiverProblématique du référencement et du déploiementUne problématique souvent vécu par les développeurs sous SharePoint est de gérer facilement le déploiement et le test. En effet, tout projet SharePoint consiste à développer une nouvelle fonctionnalité à intégrer dans le moteur de génération, ce qui est bien différent de compiler/debugger une application autonome.Même si votre code est clair et précis, tant qu’il n’est pas déployé et intégré par le moteur SharePoint, il n’est pas utilisable. Si nous reprenons le cas du?Feature Receiver, un déploiement mal assuré vous conduira à une Feature fonctionnelle mais qui n’exécute aucun événement…Par expérience, il est mieux de travailler en 2 temps?: préparer votre projet complet avec l’intégration SharePoint, puis le déployer avec les scripts. Ensuite, seulement, commence le ??véritable?? développement. Ce principe de précaution part d’un postulat très simple?: Si votre fonctionnalité se déploie une fois sous SharePoint, elle se déploiera toujours quelque soit le code métier attaché. En séparant et priorisant l’intégration SharePoint en premier, vous vous assurez un déploiement rapide et sur. Ensuite, vous pourrez vous concentrez uniquement sur la partie code et développement, sans craindre d’interférence avec la plateforme sous jacente. En cas d’erreur, une fois déployé, vous savez déjà que le souci ne peut venir que depuis votre code et non le manifest ou la méthodologie employée. Si vous ne séparez pas les étapes, vous devez traquer votre erreur depuis la plus petite ligne de XML de votre projet jusque dans les profondeurs de votre code…Bien sur, si votre Feature Receiver n’implémente que la structure de classe, il sera difficile de le tester. Le plus simple reste de générer un log dans l’event viewer Ecrire dans le journal des événementsusing System.Diagnostics;… string sSource;string sLog;string sEvent; sSource = "Log SharePoint";sLog = "Feature Receiver";sEvent = "Activation Coach";if (!EventLog.SourceExists(sSource))EventLog.CreateEventSource(sSource,sLog);EventLog.WriteEntry(sSource,sEvent);EventLog.WriteEntry(sSource, sEvent,EventLogEntryType.Warning, 234);…éférer votre classe dans la FeatureMaintenant vous pouvez compilez votre projet de code et donc obtenir une DLL ainsi que son nom fort. Un simple coup d’?il sur Reflector nous donne la bonne information?:SharePointFeature_Advanced,Version=1.0.0.0,Culture=neutral,publicKeyToken=e727ec7a42e5a6a9Il existe une alternative si vous préférez rester centré sur Visual Studio : utiliser les commandes externes avec une ligne de commande sur l’outil de signature sn.exeLigne de commande?: C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\sn.exeArgument?: -Tp "$(TargetPath)" Une fois votre classe compilée, un simple appel à cette commande externe vous permet des récupérer les identifiants de clés de l’assemblée?(version token et complexe)Notre code de démo s’appuie sur 4 Features et 4 Receiver le tout dans le même projet. Pour faire le référencement, il nous reste plus qu’à référencer l’assemblée et les 4 classes de Receiver dans les 4 manifestes de notre démo. On utilise, bien sur, le nom fort et le type de classe des 4 classes dans les fichiers Feature.xml via les attributs ReceiverAssembly et ReceiverClassFeature.xml du dossier : 12\TEMPLATE\FEATURES\CoachAutoDelete\<?xml version="1.0" encoding="utf-8"?><Feature Id="cbefa107-97ef-4b92-be00-a89d6ab22dad" Title="Coach - Advanced Auto Delete" Description="Feature that adds lists and documents, then automaticaly delete the files when it is disabled." Version="12.0.0.0" Hidden="FALSE" Scope="Web" DefaultResourceFile="core" ImageUrl="Wygwam/StramitFeature.gif" ReceiverAssembly="SharePointFeature_Advanced, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e727ec7a42e5a6a9" ReceiverClass="SharePointFeature_Advanced.AutoDelete_Receiver" xmlns=""><ElementManifests>…Feature.xml du dossier : 12\TEMPLATE\FEATURES\CoachCustomAction\<?xml version="1.0" encoding="utf-8"?><Feature Id="1cc074f3-27ee-4323-a84b-bb1e80da1fc8" Title="Coach - Advanced Custom Action" Description="Feature that brings a new hierarchical elements into the custom actions. " Version="12.0.0.0" Hidden="FALSE" Scope="Web" DefaultResourceFile="core" ImageUrl="Wygwam/StramitFeature.gif" ReceiverAssembly="SharePointFeature_Advanced, Version=1.0.0.0, Culture=neutral,PublicKeyToken=e727ec7a42e5a6a9" ReceiverClass="SharePointFeature_Advanced.CustomAction_Receiver" xmlns=""> <ElementManifests>…Feature.xml du dossier : \12\TEMPLATE\FEATURES\CoachCustomTabs\<?xml version="1.0" encoding="utf-8"?><Feature Id="5a6d1f15-581e-4f06-98d5-173372711f28" Title="Coach - Advanced Custom Tabs" Description="Feature that adds a custon tabs and manipulates some webparts." Version="12.0.0.0" Hidden="FALSE" Scope="Web" DefaultResourceFile="core" ImageUrl="Wygwam/StramitFeature.gif" ReceiverAssembly="SharePointFeature_Advanced, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e727ec7a42e5a6a9" ReceiverClass="SharePointFeature_Advanced.CustomTabs_Receiver" xmlns=""> <ElementManifests>…Feature.xml du dossier : \12\TEMPLATE\FEATURES\CoachMasterPageChanger\<?xml version="1.0" encoding="utf-8"?><Feature xmlns=""Id="4CA24A8F-D2E1-4781-BB61-E450A2091A7B"Title="Coach - Advanced Master Page Changer"Description="Feature that adds and applies a new master page and recursively (subwebs). "Version="12.0.0.0"Hidden="FALSE"Scope="Web"DefaultResourceFile="core"ImageUrl="Wygwam/StramitFeature.gif"ReceiverAssembly="SharePointFeature_Advanced, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e727ec7a42e5a6a9"ReceiverClass="SharePointFeature_Advanced.MasterPageChanger_Receiver"><ElementManifests>…Batchs de déploiement d’une FeatureVos Features et votre assemblée sont désormais prêtes à être déployées. Dans la continuité des autres coachs, nous utiliserons des scripts afin d’automatiser le processusCette opération doit se faire obligatoirement par script via l’outil de gestion en ligne de commande STSADM.stsadm.exe -o installfeature -filename [NomDuDossierDeFeature]\feature.xmlEnsuite vous pouvez activez la Feature depuis l’interface de gestion de SharePoint.Remarque?: pensez toujours à désactiver, désinstaller la Feature si vous travaillez toujours sur le même site. A la différence du mode ??force?? d’installfeature, vous êtes sur que votre configuration SharePoint reste propre et saine.Le script est évidemment similaire à celui des Features vu que nous travaillons encore sur une Feature. La petite différence est d’ajouter aussi la copie de l’assemblée dans le répertoire applicatif SharePoint.Vous avez 2 options possiblesProduction?: la DLL doit être en GAC. Cependant, vous ne pouvez utiliser de copy direct, le répertoire de destination étant un peu spécial. Vous devez utiliser l’utilitaire GACUTILS.EXE%GACUTIL% /f /i bin\***.dllChemin de l’utilitaireC:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exeDebug & test : Comme la Feature a un niveau de scope Web, vous pouvez aussi utiliser le BIN du site Web. Ce qui est plus souple pour les opérations de debug dans un premier temps. Dans ce cas, un simple Xcopy suffitBatch de déploiement dans le sous répertoire Batchs de la solution cd ..cd 12@echo offECHO "-- FULL Deploy of the solution --"@SET SPDIR="c:\program files\common files\microsoft shared\web server extensions\12"@SET FEATUREPath="CoachCustomAction"@SET DLLName="SharePointFeature_Advanced"@SET URLWss=""@SET PATHWss="C:\Inetpub\wwwroot\wss\VirtualDirectories\141"@SET GACUTIL="C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil.exe"xcopy TEMPLATE %SPDIR%\TEMPLATE /s /yxcopy Resources %SPDIR%\Resources /s /yxcopy ..\bin\debug %PATHWss%\bin /s /yREM %GACUTIL% /f /i ..\bin\debug\ ECHO "deactivatefeature"%SPDIR%\bin\stsadm.exe -o deactivatefeature -filename %FEATUREPath%\feature.xml -url %URLWss% -forceECHO "uninstallfeature"%SPDIR%\bin\stsadm.exe -o uninstallfeature -filename %FEATUREPath%\feature.xml -forceECHO "installfeature"%SPDIR%\bin\stsadm.exe -o installfeature -filename %FEATUREPath%\feature.xml -forceECHO "activatefeature"%SPDIR%\bin\stsadm.exe -o activatefeature -filename %FEATUREPath%\feature.xml -url %URLWss% -forcePausecscript.exe c:\windows\system32\iisapp.vbs /a "SharePoint - 141" /rREM IISRESETL’utilisation des commentaires avec REM permet d’invalider certaines parties du code. Bien pratique quand vous ne voulez que redéployer les fichiers .Net sans devoir relancer entièrement le processus de désinscription/inscription. Test et développement?: comment gagner du temps??Désormais, votre projet Feature est quasiment fini, vous pouvez implémentez votre code métier. Le projet contient?:Une structure 12Une FeatureUne clé de signatureUne classe implémentant SPFeatureReceiverLe Manifeste de Feature possède les références aux éléments du ReceiverLes scripts de déploiementNous pourrions nous arrêter ici et enchainer avec divers exemples d’implémentation. Cependant, ce serait rater un Best Practice bien utile en phase de déme vous le savez certainement, SharePoint 2007 est, à la base, une application et même assez complexe et lourde en mémoire.Chaque test ou déploiement de code métier demande un recyclage de pool et implique que le site Web doit se recharger. Soit en pratique, un temps de chargement bien long (en moyenne 15-40 secondes) de votre navigateur pour afficher votre site SharePoint.On est loin des habitudes du développeur qui use et abuse du F5 pour voir son fonctionner son code (surtout en terme de productivité).Il est cependant possible de contourner cette problématique du rechargement de SharePoint lors de vos développements. C’est en fait une astuce très simple héritée des best practices et autres patterns de développement SharePoint 2007 est en soit une application .Net qui va consommer votre code métier depuis l’interface des Features. Comme le ferait aussi une classique application Winform ou console avec une simple assemblée .Net. Comme le projet de Feature Receiver reste à la base un projet de classe, rien ne vous empêche de séparer votre code métier de votre classe Receiver en l’encapsulant dans une classe de service consommée par les classes implémentant SPFeatureReceiver. Dans ce tutoriel, tous les exemples implémentent une classe ??FeatureEngine?? pour exécuter les diverses actions des divers Features ReceiverUne fois cette séparation effectuée, vous pouvez très bien ajouter un projet Winform à votre solution qui ne servira que d’interface de test à votre classe de serviceAinsi vous pourrez tester et débugger votre code métier directement dans Visual Studio avec point d’arrêts et autres techniques sans même vous préoccuper de la problématique SharePointSympathique non?? En tout cas bien plus simple et pratique?que de recharger un processus !Cependant, il faut respecter une petite règle de fonctionnement?: il faut passer en paramètre à vos diverses méthodes de classe de service le contexte SharePoint en externe.Ainsi dans le cas, de votre application Winform de test vous pouvez utiliser ce sample, en vous basant sur l’url de votre site de testUtilisation hors d’un contexte dans votre application de test //utilisation de l'adresse compléte SPSite site = new SPSite("") SPWeb web = site.OpenWeb() //utilisation de la classe de service Feature_Engine Eng = new Feature_Engine(); Eng. AddNavigationNodes(web); …En ce qui concerne votre Feature, il suffit de rajouter une classe qui elle implémente SPFeatureReceiver et fera l’appel à la classe de service Utilisation dans la classe implémentant SPFeatureReceiver //utilisation des propriétés de Feature SPWeb web = properties.Feature.Parent as SPWeb; //Initialize the feature engine engine = new Feature_Engine(); //Add some navigation items on the top navigation page engine.AddNavigationNodes(web); …Ainsi, vous pouvez séparer dans vos projets tout ce qui est spécifique au développement SharePoint du code métier en différent projet/classes sans perdre vos habitudes de développement .Net Cette technique est réellement utile et facile pour être conseillée dans la plupart des développements SharePoint orienté code. De plus, une fois un composant SharePoint déployé et fonctionnel, vous pouvez vous focaliser uniquement sur la classe de code, et ne redéployer que la DLL si besoin.Développement?: quelques exemple de codeMaintenant que la conception d’une Feature avec code n’est plus un secret, il est temps de se focaliser sur le code métier propre au métier du déme décris avant, ce code métier est factorisé dans une classe de service unique appelé depuis les différentes classes des Features de démo de ce tutoriel.Ces démos sont dans la suite du coach N°3 sur les Features dans le sens qu’elle reprenne une partie de l’approche fonctionnelle couverte précédemment. Les Features Receiver que nous allons parcourir viennent justement les compléter, les étendre dans leur scénario originel?: Personnalisez un modèle de site SharePoint.Le résultat sera donc double?: 4 samples de code complets dans un modèle enrichi depuis 3 tutorielsGestion de la navigation et des WebPartsCette Feature avec Code permet d’enrichir facilement l’accueil d’un site SharePoint.En premier, elle pilote la création d’onglet supplémentaire dans la barre de navigation de SharePoint 2007. Ensuite, elle reconfigure la page à WebPart d’accueil en modifiant sa collection de WebPart.Le code n’as que le but de présenter des fonctionnalités de base, mais il peut être connecté à un système de paramétrage externe comme une base de donnée afin de le rendre plus ??générique?? ? Cette Feature ne contient qu’une seule classe événementielle mais interagit de 2 manières totalement distinctes sur le site SharePoint?: Navigation et WebPart. Les 2 actions sont 2 méthodes publiques de la classe de service mais les appels sont regroupés dans la même classe Receiver. Il aurait été peut être plus judicieux de créer deux Features indépendantes pour chaque action et activer les 2 via une troisième de regroupement. Cependant, comme vous le constaterez dans la démo, le code final reste assez simple. Pourquoi donc rajouter encore de la complexité en multipliant les Features XML?? A vrai dire, tout dépend de votre découpage projet et non de la nature technique du projetAjout d’onglet de navigationEn pratique, le Feature Receiver génère de nouveau n?uds de navigation dans la collection de n?uds de la barre d’onglet?: web.NavigationBarL’activation de la Feature ajoute 2 nouveaux onglets?: Portails et recherche ainsi que des sous niveaux vers diverses adressesLa classe CustomTabs_Receiver.cs déclare l’événement et appelle la classe de service Feature Receiver?: Activation public override void FeatureActivated(SPFeatureReceiverProperties properties) { try { SPWeb web = properties.Feature.Parent; //Initialize the feature engine engine = new Feature_Engine(); //Add some navigation items on the top navigation page engine.AddNavigationNodes(web); //Add some webparts to the default page engine.AddWebPart(web); engine.UpdateWebPart(web); } catch (Exception ex) { System.Diagnostics.EventLog el = new System.Diagnostics.EventLog(); el.Source = "CustomTabs_Receiver - FeatureActivated"; el.WriteEntry(ex.Message); } } A noter la gestion d’erreur via l’observateur d’événement de Windows gr?ce à la classe System.Diagnostics.EventLog . Dans le cas de MOSS 2007, il est possible d’utiliser la classe PortalLog pour ajouter ses propres logs dans ceux de la plateforme SharePoint 2007. System.Diagnostics.EventLog’ajout des n?uds de navigation est assez aisé, il faut simplement compléter la collection des n?uds de navigation du site en cours avec de nouvelles instances de SPNavigationNode. A noter que cette collection est hiérarchique et peut donc gérer plusieurs sous niveaux.Classe de service?: AddNavigationNodes public void AddNavigationNodes(SPWeb web) { // Do not dispose web ! // Get the current site to update the TopNavigationBar SPNavigationNodeCollection topNav = web.NavigationBar; // Dropdown menu for custom links SPNavigationNode DropDownMenuPortail = new SPNavigationNode("Portails", "", false); topNav[0].Children.AddAsLast(DropDownMenuPortail); // Add the children (links) DropDownMenuPortail.Children.AddAsLast(new SPNavigationNode("Portail commercial", "", true)); DropDownMenuPortail.Children.AddAsLast(new SPNavigationNode("Portail partenaire", "", true)); DropDownMenuPortail.Children.AddAsLast(new SPNavigationNode("Portail entreprise", "", true)); // create dropdown menu for search pages SPNavigationNode DropDownMenuSearch = new SPNavigationNode("Recherche", "", false); topNav[0].Children.AddAsLast(DropDownMenuSearch); // Add the children (links) DropDownMenuSearch.Children.AddAsLast(new SPNavigationNode("Google", "", true)); DropDownMenuSearch.Children.AddAsLast(new SPNavigationNode("Live", "", true)); DropDownMenuSearch.Children.AddAsLast(new SPNavigationNode("Yahoo", "", true)); } …Une Feature se doit aussi de gérer l’activation que sa désactivation, soit, pouvoir supprimer les nouveaux onglets si besoinDans ce cas, il nous suffit de supprimer les n?uds pères que sont Portails et Recherche en parcourant la collection de n?uds de navigation.RemoveNavigationNodes public void RemoveNavigationNodes(SPWeb web) { // Do not dispose web ! // Get the top navigation bar SPNavigationNodeCollection topNav = web.NavigationBar; // Delete the items for (int i = topNav[0].Children.Count - 1; i >= 0; i--) { if (topNav[0].Children[i].Title == "Portails" || topNav[0].Children[i].Title == "Recherche") { // delete node topNav[0].Children[i].Delete(); } } }Gestion des WebPartEn CAML, il est possible d’intégrer les WebParts lors de la création des pages à WebPart (n?uds MODULE, FILE, ALLUSERSWEBPART). Cependant, la déclaration est purement statique et non paramétrable.Si vous gérez l’ajout, voir la modification des WebParts via le code, vous pouvez piloter entièrement l’organisation et le paramétrage des composants de vos pages à WebPart En pratique, il faut récupérer l’instance de la page à WebPart que vous souhaitez modifier. Ensuite, gr?ce à l’objet SPLimitedWebPartManager de la page, vous accédez aux différentes WebParts ainsi qu’à leurs propriétés.Pour un ajout de WebPart, il suffit de créer un objet au type de la WebPart, préciser ses propriétés et l’ajouter à la classe de gestionPour une modification, il faut d’abord identifier la bonne instance dans la collection des WebParts de la page en les testant sur le type de classe. Ensuite, vous pouvez modifier les propriétés de celle-ci et sauvegardez le tout via la classe de gestionFeature Receiver?: Activation public override void FeatureActivated(SPFeatureReceiverProperties properties) { try { SPWeb web = properties.Feature.Parent as SPWeb; //Initialize the feature engine engine = new Feature_Engine(); //Add some navigation items on the top navigation page engine.AddNavigationNodes(web); //Add some webparts to the default page engine.AddWebPart(web); engine.UpdateWebPart(web); } } catch (Exception ex) { System.Diagnostics.EventLog el = new System.Diagnostics.EventLog(); el.Source = "CustomTabs_Receiver - FeatureActivated"; el.WriteEntry(ex.Message); } }Ajout d’une WebPart ??éditeur de contenu?? public void AddWebPart(SPWeb web) { // Do not dispose web ! try { SPFile page = web.GetFile("default.aspx"); SPLimitedWebPartManager mgr; mgr = page.GetLimitedWebPartManager(PersonalizationScope.Shared); //-- Add Web Part to Left Zone // Create the webpart ContentEditorWebPart webpart = new ContentEditorWebPart(); webpart.Title = "Site de présentation pour le Coach par code"; webpart.ChromeType = PartChromeType.None; webpart.AllowClose = false; // Initialize the content property XmlDocument doc = new XmlDocument(); string ns1 = ""; XmlElement elm = doc.CreateElement("Content", ns1); elm.InnerText = "<FONT size=4><U>Bienvenue sur ce site personnalisé par code !</U></FONT>"; webpart.Content = elm; // Add the webpart in the left zone mgr.AddWebPart(webpart, "Left", 0); } catch (Exception) { } } Dans cet exemple, nous utilisons la classe ContentEditorWebPart, soit la WebPart éditrice de contenu. Pour préciser son contenu HTML, nous utilisons une classe XML (donc un format XHTML) au format XmlElement.Modification d’une WebPart ??Image? public void UpdateWebPart(SPWeb web) { // Do not dispose web ! try { SPFile page = web.GetFile("default.aspx"); SPLimitedWebPartManager mgr; mgr = page.GetLimitedWebPartManager(PersonalizationScope.Shared); // Get the WebPart image foreach (System.Web.UI.WebControls.WebParts.WebPart webpart in mgr.WebParts) { if (webpart.GetType().Equals(typeof(Microsoft.SharePoint.WebPartPages.ImageWebPart))) { // Update the properties webpart.Title = "Webpart modifiée par code !"; ((ImageWebPart)webpart).ImageLink = "_layouts/Images/logo-wygwam.gif"; // Apply modifications web.AllowUnsafeUpdates = true; mgr.SaveChanges(webpart); web.AllowUnsafeUpdates = false; break; } } } catch (Exception) { } }L’objectif était de pouvoir modifier la WebPart image d’accueil du site par une plus personnel. Le test a été fait sur le type ImageWebPart. Comme l’action se trouve en dehors du contexte d’execution classique du site SharePoint, il faut passer avant en mode de mise à jour ??unsafe?? pour faire la sauvegarde?: mgr.SaveChanges(webpart);Ajout d’action personnalisé ??Custom Action??Cet exemple est un peu plus original. Il ne s’agit pas vraiment d’un Feature Receiver mais de l’utilisation d’un contr?le Web pour personnaliser le menu d’action de site.Pour ajouter des éléments à ce menu, il est possible de le faire en CAML gr?ce aux n?uds ??CustomAction??. Seulement, vous ne pouvez ajouter que de simples liens avec un ic?ne.En utilisant un contr?le Web personnalisé, vous pouvez introduire un comportement totalement différent comme un menu déroulant purement dynamique et contextuelPour illustrer cet exemple, le choix a été de compléter le menu d’action avec un accès direct aux écrans de paramétrage des diverses listes collaboratives. Soit un accès bien plus rapide pour les administrateurs de contenu. Bien sur, l’énumération des différentes listes est dynamique.Nous n’avons pas utilisé de Feature Receiver mais une simple classe de WebControl que nous avons intégré dans notre assemblée?: CustomAction_ControlWebControl pour le menu d’actionusing System;using System.Collections.Generic;using System.Text;using Microsoft.SharePoint.WebControls;using Microsoft.SharePoint;namespace SharePointFeature_Advanced{ class CustomAction_Control : System.Web.UI.WebControls.WebControl { protected override void CreateChildControls() { // Menu option definition SubMenuTemplate listSettings = new SubMenuTemplate(); listSettings.Text = "List Settings"; listSettings.Description = "Manage lists"; listSettings.ImageUrl = "/_layouts/images/lg_ICASCX.gif"; // Add the lists foreach (SPList list in SPContext.Current.Web.Lists) { if (!list.Hidden) { MenuItemTemplate listItem = new MenuItemTemplate(); listItem.Text = list.Title; listItem.Description = string.Format( "Manage list: {0}", list.Title); listItem.ImageUrl = list.ImageUrl; string url = string.Format( "{0}/_layouts/listedit.aspx?List={{{1}}}", SPContext.Current.Web.Url, list.ID.ToString()); listItem.ClientOnClickNavigateUrl = url; listSettings.Controls.Add(listItem); } } // Add custom static links MenuItemTemplate staticListItem = new MenuItemTemplate(); staticListItem.Text = "All lists"; staticListItem.Description = string.Format("Manage all lists"); staticListItem.ImageUrl = "/_layouts/images/allcontents.png"; string urlStatic = string.Format("{0}/_layouts/mcontent.aspx", SPContext.Current.Web.Url); staticListItem.ClientOnClickNavigateUrl = urlStatic; listSettings.Controls.Add(staticListItem); // Add the list this.Controls.Add(listSettings); } }}C’est un contr?le web de type composite?: il crée son propre contenu en instanciant plusieurs contr?les enfants via la méthode CreateChildControls. Le control est assez simple?: il crée différents menu d’action de type MenuItemTemplate dans une instance de sous menu SubMenuTemplate selon les diverses listes du me le contr?le Web s’exécute dans l’instance du site SharePoint, vous pouvez utiliser le contexte SharePoint courant via l’objet SPContext et parcourir les différentes listes du site?: Web.ListsL’accès aux écrans de paramétrage est générique?: chaque liste pointe vers la page d’admin SharePoint?: /_Layouts/Listedit.aspx. Puis finalement, Il suffit de préciser par querystring l’identifiant unique de la liste à éditer via SPList.IDContr?le composite que le contr?le Web est prêt et compilé, nous pouvons l’intégrer dans le site SharePoint via le CAML d’action de la Feature. Il suffit juste de le déclarer dans le n?ud CustomAction avec le nom fort de l’assemblée et le type de classElement.xml de la Feature<?xml version="1.0" encoding="utf-8" ?><Elements xmlns=""><CustomAction Id="76BA3281-0C8A-431e-B2DB-58A65A347A00" Location="Microsoft.SharePoint.StandardMenu" GroupId="SiteActions" ControlAssembly="SharePointFeature_Advanced, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e727ec7a42e5a6a9" ControlClass="SharePointFeature_Advanced.CustomAction_Control"></CustomAction></Elements>Une fois votre Feature déployée et activée, le contr?le sera disponible dans le menu d’action au lieu d’un simple lien statique Attention, SharePoint 2007 applique les principes SD3 de la politique de sécurité de Microsoft?: Secure by Default, Secure by Deployment, Secure by Design.Ainsi, le serveur Web SharePoint n’exécute aucun contr?le Web qui n’a pas été déclaré comme SAFE par l’administrateur. Comme nous ajoutons un nouveau contr?le Web dans le menu d’action, il faut absolument le déclarer avant de le tester et augmenter le niveau de sécurité d’exécution du site.Tout d’abord, il faut rajouter un n?ud ??SafeControl?? dans la section ??Configuration/SharePoint/SafeControls?? du Web.Config de votre Web Application. Cette déclaration s’appuie sur le nom fort de l’assemblée, le namespace et le type du contr?le web.Ajout du SafeControl dans le Web.config<SafeControls> <SafeControl Assembly="SharePointFeature_Advanced, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e727ec7a42e5a6a9" Namespace="SharePointFeature_Advanced" TypeName="*" Safe="True" /></SafeControls>Ensuite, pour élever le niveau d’exécution, il faut modifier l’attribut level du n?ud trust. Par défaut, le niveau WSS_Minimal restreint l’exécution de code métier aux seules assemblées Microsoft.SharePoint. En utilisant le niveau WSS_Medium, votre code sera accepté sans souci.Changement de trust dans le Web.config<trust level="WSS_Medium" originUrl="" />Si votre code s’appuie sur diverses assemblées riches pour s’exécuter, le niveau WSS_Medium peut être insuffisant. Normalement, l’idéal serait de déclarer le CAS (Code Access Security) de votre code, soit l’ensemble des permissions nécessaires au fonctionnement de votre code. Il existe des alternatives bien plus simples dans le cadre des machines de développement?:Copier votre assemblée dans le GACElever le niveau d’exécution avec FullDans les 2 cas, votre assemblée aura le maximum de privilège pour son exécutionChangement de Master PageDans le dernier tutoriel, la dernière Feature permettait d’ajouter à l’activation 3 nouvelles Master Pages dans la galerie des Master Pages du site. Cependant, il était impossible de déclarer l’une d’elle comme la nouvelle référence. L’ajout d’un Feature Receiver pour automatiser ce processus est donc un vrai plusCette démo va même bien plus loin, elle permet d’affecter aussi la nouvelle Master Page à tout les sous site. La base de la Feature est une Feature classique avec, en élément, un Module d’ajout de fichier Master Page vers la galerie des pages maitres?:Element de la Feature<?xml version="1.0" encoding="utf-8" ?><Elements xmlns=""> <Module Url="_catalogs/masterpage" Path="MP" Name="MasterPages" List="116"><File Url="default_G_Advanced.master" Type="GhostableInLibrary" /> </Module></Elements>La suite repose sur un Feature Receiver qui vient compléter le CAML en appliquant la nouvelle Master Page via récursivité sur les sites et sous sites en cours Pour rendre ce Feature Receiver un peu plus dynamique, le nom même de la Master Page a été externalisé comme paramètre. En créant une nouvelle Feature avec un nouvelle Master Page pour, par exemple, supporter une nouvelle charte graphique, il serait possible de réutiliser la même assemblée sans avoir à la recoder ou la modifier. Il suffit de changer le paramètre de nom de Master Page. En pratique, il s’agit d’utiliser les propriétés de Feature via son manifest XML. Ensuite, on récupère les données via la classe SPFeatureProperty et le fameux properties.Feature Exemple?: Déclaration d’une nouvelle propriété?dans le Feature.xml<?xml version="1.0" encoding="utf-8"?><Feature xmlns=""Id="4CA24A8F-D2E1-4781-BB61-E450A2091A7B"Title="Coach - Advanced Master Page Changer"Description="Feature that adds and applies a new master page and recursively (subwebs)."…><ElementManifests><ElementManifest Location="elements.xml"/></ElementManifests><Properties><Property Key ="defaultMasterUrl" Value="/_catalogs/masterpage/default.master"/><Property Key ="customizedMasterUrl" Value="/_catalogs/masterpage/default_G_Advanced.master"/><Property Key ="FilesToDelete" Value="default_G_Advanced.master"/></Properties></Feature>Récupération des paramètresSPFeatureProperty fp = (SPFeatureProperty)properties.Feature.Properties[CustomizedMasterUrlProperty];Le changement d’une Master Page d’un site SharePoint n’est pas complexe : c’est le r?le de la propriété MasterUrl de l’objet SPWeb. Votre code doit juste préciser l’url du fichier .Master à utiliser en référence. Comme chaque page ASPX du site utilise un token spécifique à cette propriété, la mise à jour est automatique.Toujours dans l’esprit des Best Practice avec la notion d’activation et désactivation, il est important de stocker temporairement le chemin de la Master page en cours d’utilisation. Ainsi, quand vous désactiverez la Feature, vous pouvez gérer aussi la remise à zéro des sites en réaffectant leur Master Page original plut?t que vous basez forcément sur la Default.master d’origine Microsoft.Ainsi, nous utilisons le propertybag de l’instance du SPWeb en cours, pour servir de cache de nos adresses de master Page SPWeb.AllProperties gestion du changement des sous sites est opérée par un appel récursif sur la même méthode changeWebMasterPage en parcourant la collection des sous sites via SPWeb.WebsApplication de la nouvelle MasterPage private void changeWebMasterPage(SPWeb web, String defaultMasterPage, String customMasterPage, bool isActivation) { if (isActivation) { if (!String.IsNullOrEmpty(customMasterPage)) { //Save the current properties web.AllProperties["OldMasterUrl"] = web.MasterUrl; web.AllProperties["OldCustomMasterUrl"] = web.CustomMasterUrl; web.MasterUrl = customMasterPage; web.CustomMasterUrl = customMasterPage; } } else { deactivateWeb(web, defaultMasterPage); } web.Update(); //Apply recursively foreach (SPWeb subWeb in web.Webs) { changeWebMasterPage(subWeb, defaultMasterPage, customMasterPage, isActivation); } }Il existe une autre méthode: web.GetSubwebsForCurrentUser. Elle permet de parcourir tout les sous sites d’un site SharePoint mais à la différence de web.Webs, elle énumère seulement ceux auxquels l’utilisateur a accès. Très pratique?dans le cas ou vous concevez une application à destination des utilisateurs non administrateur SharePoint comme un menu arborescent de navigation par exemple.Le reste du code n’est pas documenté car très général. Il ne s’agit que de construction d’URL et d’appel de la méthode d’affectation des propriétés.En ce qui concerne la désactivation, il faut gérer la réaffectation de l’ancienne adresse de Master Page. Le stockage des URLs dans le propertybag du SPWeb est très utile. En testant sur leur existence, nous pouvons consolider le code en une seule fonction d’application de Master Page ? changeWebMasterPage?? et ne gérer la désactivation que dans une méthode spécifique indépendante de toute récessivité ou contexte.Récupération des paramètres private void deactivateWeb(SPWeb web, String defaultMasterPage) { if (web.AllProperties.ContainsKey("OldMasterUrl")) { string oldMasterUrl = web.AllProperties["OldMasterUrl"].ToString(); try { bool fileExists = web.GetFile(oldMasterUrl).Exists; web.MasterUrl = oldMasterUrl; } catch (ArgumentException) { web.MasterUrl = defaultMasterPage; } string oldCustomUrl = web.AllProperties["OldCustomMasterUrl"].ToString(); try { bool fileExists = web.GetFile(oldCustomUrl).Exists; web.CustomMasterUrl = web.AllProperties["OldCustomMasterUrl"].ToString(); } catch (ArgumentException) { web.CustomMasterUrl = defaultMasterPage; } web.AllProperties.Remove("OldMasterUrl"); web.AllProperties.Remove("OldCustomMasterUrl"); } else { web.MasterUrl = defaultMasterPage; web.CustomMasterUrl = defaultMasterPage; } }Pour bien finaliser le code, il ne faut pas oublier de supprimer les propriétés ajoutées dans le PropertyBag une fois inutile?: ces données sont sérialisées dans l’instance SPWeb, sous entendu, stockées dans la base de contenu du serveur.Suppression des fichiers ajoutésCe dernier exemple vient en complément de la Feature d’ajout des Master Page. En effet, le précédent exemple gérer certes l’ajout et la restauration des paramètres du SPWeb mais il ne supprime pas les fichiers .master devenus inutiles. Dans le système CAML, il existe une garde fou afin de protéger l’intégrité des sites SharePoint. La désactivation d’une Feature CAML ne supprime jamais les ajouts ou création de contenu. Ainsi, si vous créez une Feature qui génère plusieurs listes et/ou ajoute des fichiers web ou office dedans, ils ne seront jamais supprimés lors de la désactivation.Imaginez le cas contraire ou lors d’une mauvaise manipulation, vous purgez réellement le contenu documentaire de votre portail …Cependant, la contre partie est simple?: votre site peut stocker plein de fichiers devenus complètement inutiles dans le temps.Cette dernière démo vous présente un Feature Receiver générique qui peut justement supprimer les fichiers ajoutés par la Feature dans la galerie des Master Page.Il existe plusieurs méthodes pour supprimer des éléments dans un site SharePointSuppression des items dans une liste?: SplistItem.Deleteforeach (SPListItem item in MyList.Items){ item.Delete}Suppression par Batch?: Web. ProcessBatchDataforeach (SPListItem item in MyList.Items){ sbDelete.Append("<Method>"); sbDelete.Append("<SetList Scope=\"Request\">" + CurrentList.ID + "</SetList>"); sbDelete.Append("<SetVar Name=\"ID\">" + Convert.ToString(item.ID) + "</SetVar>"); sbDelete.Append("<SetVar Name=\"Cmd\">Delete</SetVar>"); sbDelete.Append("</Method>");}sbDelete.Append("</Batch>");SPContext.Current.Site.RootWeb.ProcessBatchData(sbDelete.ToString());La méthode par Batch demande de créer un flux de texte de tous les fichiers à supprimer mais en termes de performance, l’opération est largement plus rapide que de le faire fichier par fichier. Tout dépend au final, du nombre de fichier à gérerDans notre exemple, le choix est base sur un nombre léger de suppression. La problématique est plus de pouvoir supprimer qu’une sélection de fichier afin d’éviter les suppressions de masse et donc de pouvoir gérer des exceptions Ainsi, pour réutiliser ce Feature Receiver dans n’importe quelle Feature, il suffit juste de définir la référence à l’assemblée, le type de classe et ajoutez la liste des fichiers à supprimer.Feature.xml<?xml version="1.0" encoding="utf-8"?><Feature Id="cbefa107-97ef-4b92-be00-a89d6ab22dad" Title="Coach - Advanced Auto Delete" Description="Feature that adds lists and documents, then automaticaly delete the files when it is disabled."… ReceiverAssembly="SharePointFeature_Advanced, Version=1.0.0.0, Culture=neutral, PublicKeyToken=e727ec7a42e5a6a9" ReceiverClass="SharePointFeature_Advanced.AutoDelete_Receiver"> <Properties> <Property Key="FilesToDelete" Value="default_R_Advanced.master,default_G_Advanced.master,default_B_Advanced.master" /> </Properties></Feature> Une alternative totalement générique aurait été de parcourir les éléments manifest en dynamique depuis le Feature Receiver pour identifier tout les fichiers chargés par Module. En effet, il est possible d’accéder au code XML de diverses actions d’une Feature depuis le Feature Receiver via la méthode properties.Feature.Definition.GetElementDefinitions. Ensuite, une simple requête XPATH sur les n?uds Modules/Files nous donnerait le reste des informations pour effectuer la suppression.Pour ce tutoriel, il était inutile de chercher un exemple forcement trop complexe, le but est surtout de vous aider à comprendre les principes et de vous épauler dans vos propres conceptionsLe code du Feature Receiver ne fait que de déstructurer la liste de fichier précise en paramètre pour créer une collection générique de string pour le transférer plus simplement vers la classe de serviceFeature Receiver public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { try { //Initialize the feature engine engine = new Feature_Engine(); //Get the files to delete List<String> filesToDelete = new List<string>(); string[] filenames = properties.Definition.Properties[propertyFileName].Value.Split(','); for (int i = 0; i < filenames.Length; i++) filesToDelete.Add(filenames[i]); //Delete files using (SPWeb web = properties.Feature.Parent as SPWeb) { //engine.DeleteFilesByCAML(web, filesToDelete); engine.DeleteFiles(web, filesToDelete); } } catch (Exception ex) { System.Diagnostics.EventLog el = new System.Diagnostics.EventLog(); el.Source = "AutoDelete_Receiver - FeatureDeactivating"; el.WriteEntry(ex.Message); } }Pour la suppression, le code de démo contient 2 variantes de sélection/suppression basées sur un générique. Les 2 sont présentées afin de vous donner une vision plus large de l’API SharePoint.Itération du contenu d’un listeIl aurait été très simple de parcourir la collection complète des fichiers de la galerie mais si jamais la liste été longue, le temps de tester chaque items sur le nom de fichier aurait été pénalisant.L’idéal, sous SharePoint 2007, sera toujours d’utiliser une requête CAML pour filtrer un jeu de donnée comme nous l’avons vu dans le chapitre 3.3.1. SPQuery fois les fichiers ciblés par la requête et l’objet SPQuery, on peut supprimer facilement le fichier par son identifiant et la méthode DeleteItemById de la ListeFiltrage et suppression via CAML public void DeleteFilesByCAML(SPWeb web, List<String> files) { // Get items collection and delete try { foreach (string filename in files) { // Construct the query SPQuery query = new SPQuery(); StringBuilder oSb = new StringBuilder(); oSb.Append(" <Where>"); oSb.Append(" <Contains>"); oSb.Append(" <FieldRef Name='FileLeafRef' />"); oSb.AppendFormat(" <Value Type='File'>{0}</Value>", filename); oSb.Append(" </Contains>"); oSb.Append(" </Where>"); query.Query = oSb.ToString(); //Execute the query SPListItemCollection itemsCollection = web.Lists["Master Page Gallery"].GetItems(query); foreach (SPListItem item in itemsCollection) web.Lists["Master Page Gallery"].Items.DeleteItemById(item.ID); } } catch (Exception) { throw; } }Suppression par les fichiersIl y a 2 fa?ons de voir la suppression des fichiers dans une liste?: Supprimer l’élément de la liste?: SPlistItemSupprimer le fichier?: SPfileEn effet, la galerie des Master Pages est à la base une liste SPList mais surtout une liste documentaire SPDocumentLibrary. La différence est mineur mais dans notre cas très pratique, car elle permet d’accéder directement aux différents fichiers de la liste sans passer par la notion de SPListItem.La méthode est plus simple et encore plus efficace qu’une requête CAML. En remontant sur le dossier de racine de la liste documentaire, vous pouvez utilisez la collection de fichier ainsi que son indexeurSuppression via les fichiers SPFiles public void DeleteFiles(SPWeb web, List<String> files) { //Get the master page library SPDocumentLibrary docLib = web.GetCatalog(SPListTemplateType.MasterPageCatalog) as SPDocumentLibrary; //Delete each file if exists foreach (string filename in files) { if (docLib.RootFolder.Files[filename].Exists) docLib.RootFolder.Files[filename].Delete(); } }Quelques remarques cependant?:Les différents modèles de liste de base de SharePoint existent dans une énumération. On évite ainsi de devoir chercher une liste système par son nom et donc de gérer des soucis de traduction multilingue?: web.GetCatalog(SPListTemplateType.MasterPageCatalog)Retyper une classe n’est pas complexe du tout mais il faut être sur de son type de base. Un test peut être fait en amontif (docLib.RootFolder.Files[filename].Exists) docLib.RootFolder.Files[filename].Delete();Pour limiter le risque d’erreur, un test d’existence sur les fichiers est toujours conseilléif(lDoc is SPDocumentLibrary)SPDocumentLibrary docLib = (SPDocumentLibrary)lDoc ; Pour aller plus loin…Ce tutoriel a eu pour vocation de vous évangéliser sur la création et la conception de Feature Receiver SharePoint. Il a aussi servit d’introduction aux APIs SharePoint 2007Les Features Receiver, en s’intégrant dans le cycle de vie des Features, vous permet de pouvoir lier votre code métier au plus proche de la plateforme SharePoint 2007. Certes, la combinaison code métier, Feature déclarative ainsi que les options de Stapling ou de regroupement de Feature peut effrayer, du fait de l’accumulation de technologie mais permet à coup sur d’avoir une solution réelle à toute problématique technique SharePoint.Il faut cependant bien pondérer l’ajout de code métier. Les APIs SharePoint couvrent aisément l’ensemble des possibilités du framework mais elle introduit aussi des règles de gestion mémoire ainsi qu’une méthodologie bien particulière?:Gestion de la pression mémoireUtilisation du contexte SharePointOptimisation des objetsRequêtes CAML et richesse des objetsSi le modèle objet SharePoint reste clair et détaillé, il n’en est pas moins extrêmement riche. Ne négligeait pas non plus MOSS 2007 ou chaque Service métier introduit de nouveaux Namespaces et problématiques spécifiques comme Excel Services ou InfoPath.A vrai dire, il ne s’agit pas forcement d’une nouvelle problématique mais tout simplement d’accepter de découvrir et d’apprendre le fonctionnement d’un framework largement complémentaire à . Soit des espaces de noms, des modèles de compilation et du déploiement qui sont largement couverts par le kit de développement de SharePoint?:SDK WSS?V3:En ligne?: ?: MOSS 2007En ligne?: ?: tutorial cl?t quasiment le sujet des Features, cependant, vous retrouvez leur utilité tout au long de vos développements SharePoint. Qu’il s’agisse des systèmes événementiels, des timers, des WebPart et même des types de contenu, le déploiement logique sera de toute fa?on encapsulé dans une Feature. Vous découvrirez juste de nouvelles options exploitables du code CAML ou des API à travers les Features ou leurs ReceiverEn ce qui concerne les APIs, la gestion du contexte local ou distant gr?ce à l’adresse des sites vous ouvre les portes du développement avec des standards plus classiques comme?: Les smart clientsClients légerLes clients mobiles Application consoleA noter quand même les possibilités de moteur de Scripting Powershell, qui peut interagir réellement avec les API .Net. L’utilisation en script de référence vers des assemblées métiers et aussi celles de SharePoint 2007 permet la réalisation rapide de tout script de maintenance, automatisation de processus de gestion. Un véritable atout qui vous rapproche des use et coutumes en gouvernance et gestion de ferme lors des opérations de sauvegardes, administration des droits , …Rendez-vous dans le prochain atelier…Dans l’atelier 5, ??créer vos WebPart pour SharePoint??, vous allez mettre en place une solution complète sous Visual Studio d’une Feature SharePoint déployant un contr?le WebPart. Vous découvrirez les notions de contr?les Web et de leur déploiement ainsi que les bonne pratiques à leur sujet. 22860012700Requête d’interrogation type XPath.LexiqueTruc et astuceZoom sur la techniqueDéfinition d’un concept avancéRéférence MSDNAttention sécurité ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download