SharePoint 2007 : Extension Method (TryGet)

Ca fait un moment que je tripatouillais ca dans ma tete, il est temps que je vous en parle : L'utilisation des extensions de methode pour SharePoint.

Si par hasard, vous n'etes pas familier avec ce concept, vous trouverez plus d'informations sur le blog de Scott Guthrie.

Alors si vous etes comme moi (ie : Faineant), vous en avez marre de toujours devoir coder les memes choses lors de vos developpements, comme notamment ce bout de code pour afficher le nom d'une liste.

using System;

using Microsoft.SharePoint;

 

namespace SharePoint_Console_Application

{

    class Program

    {

        private const string STR_ErrorList = "ErrorList";

 

        static void Main(string[] args)

        {

            using (SPSite site = new SPSite("http://localhost"))

            {

                using (SPWeb web = site.RootWeb)

                {

                    SPList oRandomList;

                    try

                    {

                        oRandomList = web.Lists[STR_ErrorList];

                    }

                    catch (Exception ex)

                    {

                        Console.WriteLine(String.Format("La Liste {0} n'existe pas. Message : {1}", STR_ErrorList, ex.Message));

                    }

 

                    if (oRandomList != null)

                        Console.WriteLine(oRandomList.Title);

                }

            }

            Console.ReadLine();

        }

    }

}

Bien sur, vous pourriez recuperer une instance de votre liste differemment mais ce qui est important ici est de noter toute la plomberie necessaire juste pour savoir si une liste existe et eventuellement l'utiliser.

Et si, grace aux extensions de methodes, on rajoutait quelques petites fonctionnalites qui nous simplifieraient la vie ? Comme par exemple, un TryGet sur web.Lists.

using System;

using Microsoft.SharePoint;

using Phil.SharePoint.Extension;

 

namespace SharePoint_Console_Application

{

    class Program

    {

        private const string STR_ErrorList = "ErrorList";

 

        static void Main(string[] args)

        {

            using (SPSite site = new SPSite("http://localhost"))

            {

                using (SPWeb web = site.RootWeb)

                {

                    SPList oRandomList;

 

                    if (web.Lists.TryGet(STR_ErrorList, out oRandomList))

                        Console.WriteLine(oRandomList.Title);

                    else

                        Console.WriteLine(String.Format("La Liste {0} n'existe pas.", STR_ErrorList));

                }

            }

            Console.ReadLine();

        }

    }

}

De suite, c'est plus leger :)

L'extension de method TryGet ressemble a ca :

using System;

using System.Diagnostics;

using Microsoft.SharePoint;

 

namespace Phil.SharePoint.Extension

{

    public static class SPExtension

    {

        public static bool TryGet(this SPListCollection oListCollection, string name, out SPList result)

        {

            result = null;

            try

            {

                result = oListCollection[name];

                return true;

            }

            catch (Exception ex)

            {

                Trace.Write(String.Format("Extension Method TryGet : {0}", ex.Message), "Monitorable");

                return false;

            }

        }

    }

}

Alors bien sur l'implementation du TryGet est sujet a discussion, on aurait pu aussi bien faire ceci :

        public static bool TryGet(this SPListCollection oListCollection, string name, out SPList result)

        {

            result = null;

 

            foreach (SPList list in oListCollection)

            {

                if (list.Title == name)

                {

                    result = list;

                    return true;

                }

            }

            return false;

        }

Ou faire appel a d'autre methodes pour recuperer la liste...

Bref, c'est sympa mais si on veut pouvoir utiliser ce genre de methode sur d'autres objets, il va falloir copier coller le code, changer le type, bref ca va etre long, lourd et surtout source d'erreur.

Alors pourquoi ne pas aller plus loin, notamment avec l'utilisation des Generics ?

En effet, il faut savoir que la plupart des objets que l'on manipule dans SharePoint heritent de SPBaseCollection, on peut donc rajouter une methode qui sera ainsi accessible a tout les objets qui nous interessent (SPListCollection, SPUsers, SPWebs, etc..)

        public static bool TryGet<T>(this SPBaseCollection spBase, string name, out T result)

        {

            result = default(T);

            try

            {

                MethodInfo methodInfo = null;

                Type spCollectionType = spBase.GetType();

 

                methodInfo = spCollectionType.GetMethod("get_Item", new Type[] { typeof(string) });

 

                if (methodInfo == null)

                    return false;

 

                result = (T)methodInfo.Invoke(spBase, new object[] { name });

                return true;

            }

            catch (Exception ex)

            {

                Trace.Write(String.Format("Extension Method TryGet : {0}", ex.InnerException.Message), "Monitorable");

                return false;

            }

        }

Comme il n'y a pas d'interface qui lie les objets qui nous interessent a SPBaseCollection, on ne peut pas utiliser le polymorphisme et on passe donc par la reflection.

L'utilisation de la reflection reste relativement basique ici, on recupere le Type reel de l'objet spBase puis la methodInfo qui nous interesse pour ensuite l'invoquer.

Hors comme vous le savez sans doute, la reflection a un cout non negligeable en terme de performances et l'idee de ces extensions de methodes est de simplifier la vie du developpeur, pas de la compliquer en ralentissant le traitement de son code.

C'est pourquoi j'ai apporte quelques modifications au code precedent :

        private static Dictionary<Type, MethodInfo> s_GetItemMethodInfos = new Dictionary<Type, MethodInfo>();

        public static bool TryGet<T>(this SPBaseCollection spBase, string name, out T result)

        {

            result = default(T);

            try

            {

                MethodInfo methodInfo = null;

                Type spCollectionType = spBase.GetType();

 

                if (s_GetItemMethodInfos.ContainsKey(spCollectionType) == false)

                {

                    methodInfo = spCollectionType.GetMethod("get_Item",

                                    BindingFlags.InvokeMethod | BindingFlags.ExactBinding | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly,

                                    null,

                                    new Type[] { typeof(string) },

                                    null);

                    s_GetItemMethodInfos.Add(spCollectionType, methodInfo);

                }

                else

                    methodInfo = s_GetItemMethodInfos[spCollectionType];

 

                if (methodInfo == null)

                    return false;

 

                result = (T)methodInfo.Invoke(spBase, new object[] { name });

                return true;

            }

            catch (Exception ex)

            {

                Trace.Write(String.Format("Extension Method TryGet : {0}", ex.InnerException.Message), "Monitorable");

                return false;

            }

        }

On stocke les methodInfo dans un dictionnaire en static ce qui nous permettra d'eviter d'appeler GetMethod a chaque appel pour un meme objet.

L'appel a GetMethod se fait avec des BindingFlags qui permettent en theorie de limiter et d'optimiser au maximum cet appel (cf Improving Reflection Performance)

Ainsi a chaque appel, on verifie si on a deja la methodInfo correspondante au type sur lequel la methode est appelee et on invoque directement la methode si c'est le cas.

Bien sur, je ne suis pas en train de dire que ce code pourrait aller en production. Il faudrait que je fasse des vrais benchmarks pour voir exactement le cout/gain en terme de performance. De plus, le fait d'encapsuler a ce point la gestion d'erreur peut se reveler problematique ... mais ca laisse en tout cas songeur en terme de possibilite.

Finalement, je tenais a remercier (par ordre d'intervention) Olivier Nizet, Matthieu Mezil, Davy Frontigny et Jerome Laban qui ont apporte leur contribution a ce petit Proof of Concept bien sympatique.

Si vous avez des idees sur l'optimization de cette methode, je suis preneur :)

<Philippe/>

SharePoint 2007 : Personnaliser SharePoint avec les CustomActions (Partie 2)

Lors du précédent billet, je vous ai rapidement présenté une utilisation basique des CustomActions.

Mais si on veut aller plus loin, on découvre que l'on peut utiliser ses propres WebControl lorsqu'on souhaite rajouter des menus dans SharePoint. Ca laisse reveur ...

Ce post va donc vous présenter le genre de personnalisation que l'on peut obtenir avec cette méthode.

L'idée de départ est simple : je souhaite pouvoir lancer le plus simplement possible un workflow spécifique sur l'ensemble des éléments de ma liste. Comment faire  ? la preuve en images.

  • Présentation de la solution :

image

Ce projet comprend une feature, une page qui sera déployer dans les layouts et un peu code que nous allons détaillé par la suite.

  • Creation de la feature

image 

  • Creation de la CustomAction

image

Ici, je souhaite rajouter un nouveau menu au niveau de la boite à outil de ma liste dans la menu Action. Je souhaite que mon menu n'apparaisse uniquement que sur les listes (RegistrationType=List) de type librairie de document (RegistrationId=101).

  • Creation du WebControl associé

image

On va créer une nouvelle Classe qui va hériter de WebControl. Jusqu'ici que du classique.

image

L'ensemble du "vrai" travail, se fait dans la méthode CreateChildControls. Nous allons tout simplement rajouter un nouveau control de type SubMenuTemplate qui va nous permettre de rajouter un MenuItemTemplate pour chaque Workflow associé à la liste.

On récupère les workflows associés à la liste via WorkflowAssociations et on s'assure que le workflow peut être lancé (Enabled, AllowManual à True).

L'utilisation de la méthode FindListView() est une astuce développée par TheKid qui permet de circonvenir un bug avec le token {ListId} qui n'est pas forcément transformer à l'éxécution de la réquête. Plus de détails à cette adresse : http://blog.thekid.me.uk/archive/2008/04/29/sharepoint-custom-actions-in-a-list-view-webpart.aspx

Voilà la méthode en question :

image

Il ne reste plus qu'à déployer, compiler et voilà le résultat. Je sais , j'aurais pu faire un effort au niveau du désign ;)  :

image

Maintenant, il ne nous reste plus qu'à sélectionner les éléments que l'on souhaite soumettre au Workflow. Pour faire au plus simple, j'ai choisi de faire cette action dans une page générique que j'aurais déployé dans les layouts.

  • Rajout de la page qui va se charger de lancer le workflow sur chaque élément sélectionné
    • Aspx

image

Rien de transcendant ici, on ajoute simplement une CheckBoxList à cette page "type". Vous pourrez retrouver comment faire des formulaires qui gardent le "look" SharePoint sur le livre "Inside WSS 3.0" de Ted Pattison. J'en reparlerais sans doute dans les prochains posts.

A noter simplement, que cette page fait appel à l'assembly Phil.SharePoint.Workflow.CustomMenu.RunSelectedWorkflowForm dont le code est détaillé ci-dessous.

    • CodeBehind

image

Ici, on va travailler essentiellement sur la CheckBoxList, la liste d'élément et l'objet WorkflowAssociation

image

On récupère les paramètres passé dans l'URL (ListId et WFAssociationId) et on remplie la CheckBoxList.

Ce qui est un peu particulier ici est qu'il est nécessaire de faire tout un tas de vérification afin de ne pas pouvoir lancer le workflow sur un élément qui a déjà ce workflow en cours. C'est à cela que nous sert le SPFieldWorkflowStatus.

image

Ici, cette méthode lancera le workflow pour chaque élément sélectionné via la méthode StartWorkflow du WorkflowManager du site. A noter que l'on ne passe pas d'InstanciationData, ce qui peut être peu pratique pour certains workflows. Ce cas serait a traiter à l'occasion.

image

La gestion des erreurs de workflow "copié-collé" du livre de Ted Pattison.

Au final, la page donne ceci :

image

Voilà, j'espère vous avoir démontrer qu'il pouvait se révéler très intéressant de personnaliser l'interface SharePoint via les CustomAction et que grâce à l'utilisation de l'attribut ControlClass, les possibilités sont infinies :)

PS : Pour ceux qui se disent que j'aurais pu faire un copier coller de VisualStudio plutôt que des captures d'écrans. Je suis passé sous Hyper-V et Windows Serveur 2008, du coup je galère un peu pour la configuration de l'ensemble et jusqu'à présent je ne sais pas copier de ma VPC vers mon PC et j'ai quelques soucis pour échanger des fichiers entre les deux :).

<Philippe/>

SharePoint 2007 : Personnaliser SharePoint avec les CustomActions (Partie 1)

Pour ceux qui ne serait pas familier avec le concept de CustomAction dans SharePoint, je vous conseille de lire ce très bon article qui vous donnera les bases pour comprendre ce qui suit :

http://lefortludovic.developpez.com/tutoriels/sharepoint/custom-actions/

Pour résumer, on pourrait dire que le mecanisme de CustomAction permet de définir des nouveaux menus dans l'interface SharePoint très simplement.

Par exemple :

image

  • Dans la toolbar de la ListView Web Part

image

  • Dans le menu des éléments d'une liste

image

  • Dans le menu Action du site

image

Bon, je crois que vous avez compris l'idée :)

Pour ajouter ce genre de menu, rien de plus simple :

  • le fichier descriptif pour la feature

image

  • le fichier element.xml comprenant la définition de la CustomAction

image

Comme toujours, le SDK ou la MSDN sont vos amis pour comprendre de quoi il retourne (notamment pour savoir quoi mettre dans l'attribut Location)

PS : Il est aussi possible de cacher certains menus via l'utilisation des CustomAction. le problème est de connaitre le identifiants utilisés par les menus que l'on souhaite cacher. Heureusement pour vous, John Holliday s'est déjà occupé de les repertorier à cette adresse : http://johnholliday.net/resources/customactions.html

Afin de pallier au petit coté statique qu'il peut y avoir dans les URL des CustomAction, il est possible d'utiliser des token de type {ItemId}, {ItemUrl}, {ListId}, {SiteUrl}.

Maintenant que nous avons vu les bases, enchainons sur l'utilisation de l'attribut ControlClass pour définir nos propres contrôles dans les menus (dans le prochain post).

<Philippe/>

SharePoint : MVP Summit 2008 (Part 3)

Posté le lundi 21 avril 2008 00:51 par phil :: 3 commentaire(s)
Classé sous ,

Notre séjour au MVP Summit fut carrément instructif autant en terme d 'info pendant les sessions que de rencontres avec les MVPS SharePoint dans le monde.

Comme vous le savez sans doute, je ne peux malheureusement pas vous parler des sessions (NDA) mais du coup, je voulais vous montrer certaines têtes bien connues dans le monde SharePoint :

  • Andrew Connel
  • Joel Oleson
  • Maurice Prather
  • Bob Fox
  • John Holliday
  • Adam Buenz
  • Todd Bleeker
  • ...

Renaud (http://blogs.developpeur.org/themit) au centre, Adam Buenz (http://www.sharepointsecurity.com/) juste derrière lui à droite.

 IMG_0793

Ishai Sagi ( http://www.sharepoint-tips.com/) et John Holliday (http://www.johnholliday.net/) avec Todd Bleeker (http://mindsharpblogs.com/Todd) au centre.

 IMG_0795

Gat (http://www.sharepointofview.fr/) et moi-même.

IMG_0802  

Joel Oleson (http://blogs.msdn.com/joelo/)

IMG_0806

Maurice Prather (http://www.bluedoglimited.com/SharePointThoughts/default.aspx)

IMG_0809     

Le duo de choc : Bob fox (http://bobfox.securespsite.com/FoxBlog/default.aspx) et Andrew Connell (http://www.andrewconnell.com/blog/)

IMG_0817 

Brad Smith, Bob Fox et Eugene Rosenfield

IMG_0819   

Shane  Young (http://msmvps.com/blogs/shane/)

IMG_0805

Toute la team UK, Ben Rob (http://www.sharepointblogs.com/benrobb/default.aspx) , Spencer Harbar (http://www.harbar.net/), Steve Smith, (moi), Penny Coventry (http://mindsharpblogs.com/Penny/), Nick Swan (http://www.sharepointnick.com/blog/default.aspx)

IMG_0832  

Dans un tout autre style ...

IMG_0870

Ils sont mignons, j'en ai la larme à l'oeil. J'espère que Kangoo ne sera pas trop jaloux ;)

PS : Pour ceux qui s'étonnent de me voir poster à cette heure ci, le jet lag de +9 heures fait son effet :)

<Philippe/>

SharePoint : MVP Summit 2008 (Part 2)

Après un long voyage d'une dizaine d'heures, plusieurs films et un survol du GroenLand plus tard ...

IMG_0697

Nous voilà arrivés à Seattle :

 IMG_0727 IMG_0726

En attendant que les hostilités commencent, il a bien fallu se nourrir..

Bien sur, nous avons suivi le régime ultra équilibré de l'homme moderne (sans sa femme) : Hamburger et Coca à volonté :)

IMG_0730

IMG_0731

Bien sur, tout le monde est passé sur la balance avant le séjour, ca rigolera moins dans 7 jours si on continu à ce rythme là, n'est ce pas Gat ? ;)

IMG_0734

<Philippe/>

SharePoint : MVP Summit 2008 (Part 1)

Posté le samedi 12 avril 2008 10:00 par phil :: 3 commentaire(s)
Classé sous ,

Premier post d'un série qui je l'espère saura vous montrer un peu de l'intérieur de notre séjour aux US. Quand je dis "notre", je parle du séjour que les MVP de Winwise ont la chance de faire pour aller au MVP Summit 2008:

  • Florent Santin
  • Matthieu Mezil
  • Thomas Lebrun
  • Michel Perfertti
  • Christian Robert
  • Daniel Tizon (RD)
  • Gaëtan Bouveret

et moi-même.

Merci à Winwise pour nous avoir permis de faire ce séjour très instructif en perspective.

Voici la première photo du groupe (sans les retardataires :) )

IMG_0694

On espère qu'on aura une aussi bonne tête au retour. (Sauf pour Thomas qui peut pas y faire grand chose :))

<Philippe/>

SharePoint 2007 : MVP SharePoint !!

C'est avec beaucoup de plaisir et d'honneur que j'ai appris ma nomination MVP SharePoint cette apres midi.

Je tenais à remercier toutes les personnes, amis, collègues et/ou autres, qui m'ont apportées leur soutien tout au long de l'année.

PS :J'espère simplement que ce n'est pas le pire poisson d'avril qu'on m'ai jamais fait :)

<Philippe/>

SharePoint 2007 : Création de Workflow avec Visual Studio 2008 (Partie 3)

Ce billet fait suite à une session présentée durant les Techdays 2008 sur la Création d'un Workflow pour Windows SharePoint Services 3.0 avec Visual Studio 2008

Durant cette session, nous avons abordés (Julien et moi) de nombreux sujets comme :

? les avantages de Visual Studio 2008 pour le développement de workflow "SharePoint"
? les différences entre workflows séquentiel et à états.
? le design d'un workflow à états
? l'utilisation de correlation token
? les activités comme OnWorkflowActivated, Delay, ...
? la création de formulaires ASP.Net et Infopath+Form Services
? la gestion de la sécurité sur les tâches et sur les documents liés au workflow
? la gestion d'un processus d'escalade dans les deux types de workflow
? La création de types de contenu (content type) personnalisés pour votre workflow
? le packaging et le déploiement sur votre environnement.

Et bien, maintenant que les vidéos des Techdays 2008 sont disponibles, vous allez pouvoir retrouver tout ça (vidéos et slides) à cette URL: http://www.microsoft.com/france/vision/mstechdays08/WebcastMSDN.aspx?EID=6f2d454c-6e96-432c-999c-0552a6096ea7

image

Le but de cette présentation est de vous faire découvrir comment utiliser les nouvelles fonctionnalités de Visual 2008 pour créer des workflows pour SharePoint 2007, ainsi que d'apprendre les étapes nécessaires à la création d?un workflow avancé avec l?utilisation de formulaires d?instanciation, d?initiation, de tâches utilisateur, d?assignation de permissions à la volée, etc ?

Pour finir, C'était aussi l'occasion de vous montrer qu'il est possible ,grâce à Visual Studio 2008, de déployer et de débugger votre workflow dans votre environnement en un simple clic.

En attendant les articles (en cours d'écriture) qui préciseront les propos tenus lors de la présentation, vous pourrez retrouver la vidéo sur le site des Techdays 2008.

<Philippe/>

SharePoint 2007 : SharePoint Quick Launch, SPViewPermissionSetting, SPListDisplaySetting

Je viens de me rendre compte que cela fait près de 6 mois que je suis accro à un outil fait par un des membres de la communauté SharePoint française (Laurent Cotton) et que je n'en avais jamais parlé sur ce blog. D'autant plus étrange que j'en parle tout le temps en formation comme étant un des tools indispensables dans la boite à outils du SharePointeur : J'ai nommé SharePoint Quick Launch

SharePoint Quick Launch

Le concept est simple, donner accès en un clic au :

  • Répertoire 12 de SharePoint
  • Répertoire des Features
  • Ouvrir une fenêtre de commandes MS-DOS et avec le path qui pourra lancer STSADM

SharePointQuickLaunch1.jpg

De plus pour chaque Application Web liée à SharePoint, vous allez pouvoir :

  • Recycler l'application pool
  • Editer le Web.Config
  • Browser le site (lancera IE)
  • Ouvrir le répertoire IIS

SharePointQuickLaunch2.jpg

Honnêtement, j'ai pas mal d'outils sur mes VPC SharePoint mais vous pouvez être sur que c'est le premier que j'installe :)

Mais Laurent a aussi réalisé deux autres features disponibles elles aussi sur Codeplex : SPViewPermissionSettings et SPListDisplaySetting

SPViewPermissionSettings

Le concept est simple : administrer et configurer des vues pour des groupes

SPViewPermissionSetting0.gif

Après activation de la feature, un nouveau menu apparait dans l'interface d'administration de la liste, View Permission Setting (Powered ...)"
SPViewPermissionSetting1.gif

Un formulaire apparait et vous permet de spécifier des vues pour chacun des groupes existants

SPViewPermissionSetting2.gif

On voit ci-dessous ce cela vous permet d'avoir en fonction de votre groupe.

SPViewPermissionSetting3.gif
...
SPViewPermissionSetting4.gif

Et pour finir, avec SPListDisplaySetting, il règle une problématique récurrente dans le monde de la customization de formulaire, le fait d'afficher ou pas un champ d'un élément.

Pour information, il existe des solutions plus ou moins élégantes comme par exemple : More SharePoint Branding - Customisation using Javascript - Part 5, Part 1, Part 2, Part 3, Part 4

SPListDisplaySetting

SPListDisplaySetting3.jpg

Après activation de la feature, un nouveau menu apparait dans l'interface d'administration de la liste, Display settings (Powered ...)

SPListDisplaySetting1.jpg

Un nouveau formulaire apparait vous permettant de définir pour chaque mode (nouveau, édition, affichage) quand afficher les champs de la liste

  • Toujours
  • Jamais
  • Quand l'utilisateur courant fait partie (ou pas) d'un groupe SharePoint

SPListDisplaySetting2.jpg

Bref, des features sympas et un outil vraiment cool.

Ca mérite d'aller s'abonner à son blog http://sharepoint.over-blog.fr/

<Philippe/>

SharePoint 2007 : Développer des User Defined Functions pour Excel Services

Comme Adrien l'a annoncé sur son blog, nous avons co-rédigé un article sur Excel Services et les User Defined Functions.

Excel_Services

Alors si vous êtes intéressé par remplacer cette formule excel :

par celle ci :

ou que vous souhaitez simplement découvrir ce que sont les Excel Services et les User Defined Functions, je vous encourage à aller lire cet article

Bonne lecture !

<Philippe/>

SharePoint 2007 : Déploiement de WebPart et Utilisation de SPFeatureReceiver

Que faire lorsque vous avez enfin fini de développer votre WebPart ? La déployer !

Comment ? Plusieurs méthodes existes mais me connaissant, vous devez savoir que je vais parler de feature, de solution et de WSPBuilder et des VseWss.

Regardons ensemble la base de la feature pour déployer la webpart suivante (code simple car ce n'est pas le sujet de ce post) :

webpart_code

Pour déployer cette webpart vous allez utiliser une feature composé de 3 fichiers dont voici un exemple :

  • Feature.xml

    feature_xml_1
     
  • Elements.xml

    element_xml

  • [nomdewebpart].webpart

    fichier_webpart

Pour plus d'informations concernant les attributs et sections composant chacun de ces fichiers, je vous renvoie au SDK WSS 3.0  (Oui, je sais c'est facile ^^)

Au final, cette feature uploadera le fichier CleanWebpart.webpart dans la galerie de webpart de votre collection de site via la section Module compris dans le fichier elements.xml.

La problématique avec cette section Module est qu'elle uploade bien les fichiers mais ne les supprime pas lors de la désactivation de la feature. Dans certain cas, c'est le comportement souhaitable mais il peut y avoir des cas où vous souhaiteriez avoir l'effet inverse.

Pour ce faire, vous allez compléter le fichier feature.xml comme suit (Ajout de l'attribut ReceiverAssembly et ReceiverClass) :

feature_xml_full

Rajouter un nouveau fichier de type "class" (ici, nommé CleanWebpartReceiver) et le faire hériter de SPFeatureReceiver. Cette classe a 4 méthodes intéressantes :

Public method FeatureActivated Appelée après activation de la feature
Public method FeatureDeactivating Appelée lors de la désactivation de la feature
Public method FeatureInstalled Appelée après installation de la feature
Public method FeatureUninstalling Appelée lors de la désinstallation de la feature

Il ne vous restera plus qu'à overrider les méthodes qui vous intéressent (activation, désactivation, etc...) :

feature_deactivating

Le mécanisme est relativement simple :

  1. Récupération de la collection de site via les propriétés de la feature (properties.feature.parent est un SPSite car la feature a été inscrite en SCOPE = SITE)
  2. Récupération du catalogue de Webpart sous la forme d'une SPList
  3. Récupération du fichier descriptif de la Webpart (CleanWebpart.webpart) via la fonction GetWebPartFileName
  4. Suppression de la WebPart

Voyons ensemble la fonction DeleteWebPartViaCAML :

delete_webpart

Les amateurs reconnaîtront l'utilisation de l'outil CAMLViewer.

Ici on récupère, via une requête CAML, tout les éléments du catalogue de webpart qui sont liée à CleanWebpart.webpart, puis on les supprime.

Quel en est l'effet ? Dorénavant, un utilisateur ne pourra plus rajouter cette webpart dans la collection de site concernée.

Néanmoins, toute les webparts ajoutées antérieurement continuerons de fonctionner normalement (tant que la DLL sera dans le GAC).
 

Pour finir, il est intéressant de noter que l'on pourrait pousser le vice jusqu'à ajouter automatiquement la webpart sur la homePage (par exemple) du site WSS via l'utilisation du SPLimitedWebPartManager. Ce manager permet (entre autres choses) de manipuler (Ajout, Suppresion, Modification, Connection, etc...) les webparts sur une page de webpart.

feature_activated   

Bien sur, tout ceci aurait pu être fait différemment et de manière plus complète (gestion d'erreurs, commentaires ^^) mais je suis sur que vous avez saisi l'idée.

<Philippe/>

SharePoint 2007 : Features et Solutions, les outils de Création et de Déploiement (partie 2)

Ce billet fait suite au précédent sur les outils de création et de déploiement dans SharePoint où j'ai déjà présenter deux outils avec leurs avantages et inconvénient :

Maintenant, je vais vous parler d'autres outils :

Extensions CodeRush pour SharePoint

Pour ceux qui ne connaîtraient pas CodeRush (ou Refactor! Pro), il s'agit d'un Addins à Visual Studio 2005/08 développé par DevExpress. Le but de ces outils étant d'améliorer la productivité des développeurs en automatisant certaines tâches (renommage, factorisation, etc...).

Avant de commencer, je tiens à préciser que je ne rentrerai pas dans le débat du "meilleur outil " et je me concentrerai uniquement sur ces extensions de CodeRush pour SharePoint développé par Andrew Connell

Pour information, sachez simplement que CodeRush & Refactor! Pro ne sont pas gratuits (environ 250$) mais que l'addin SharePoint codé par Andrew est totalement gratuit. Voici une petite démo de CodeRush et Refactor! Pro.

Bon, vous avez saisi l'idée : CodeRush & Refactor! Pro sont censés vous faire coder plus vite. Or nous savons tous que le développement SharePoint n'est pas si commun que ça au développement C# classique (Utilisation de GUID, création de fichier XML, Event receiver, etc ...), alors en quoi, ces outils de développement générique peuvent nous aider ?

En effet, si je prend l'exemple d'une webpart de type "Hello World":

  • HelloWorld.cs (Fonctionnement de la webpart)
  • HelloWorld.webpart  (Fichier Descriptif)
  • Feature.xml (Description de la feature)
  • Elements.xml (Upload du Fichier WebPart)
  • Etc ...

Le seul fichier auquel vous apportez une réelle plus-value est HelloWorld.cs, tout le reste n'est que plomberie nécessaire à SharePoint. C'est ce raisonnement qui a pousser Andrew Connell à développer ces extensions. Voyons ce que ça a donné :

Création de GUIDS :

Si vous non plus, n'aimez pas faire : Tools >> Create GUID >> New >> Copier >> Coller >> Supprimer les accolades (si besoin)... Andrew vous propose de tapper directement dans votre fichier XML : newguid [espace]


newguid

Simple mais bien pratique en tout cas !

Création des fichiers feature.xml :

Je vous entend déjà me dire : "Ça existe déjà dans VseWss, WSPBuilder Extensions, STSDEV, etc..." Personnellement, j'apprécie le petit plus qu'est la navigation avec la touche [ENTREE] et une description lors du survol d'un élément.
Pour en bénéficier, tapez : fxml[espace] puis [entrée] pour passer d'un élémént à un autre.

fxml  

Création de fichiers feature.xml avec gestion des Features Receivers :

Même système que précédemment mais avec en plus la détection automatique de l'utilisation de SPFeatureReceiver dans votre projet et de l'ajout de la DLL générée (Full Name) dans le champ du fichier feature.xml. Le tout fait automatiquement sans passer par le non moins fabuleux outil de Lutz's Reflector pour récupérer le nom complet.

frxml  

Et encore bien d'autres fonctionnalités que vous pourrez retrouver à ces adresses :

A noter que Andrew à mis à jour récemment ces extensions. Vous trouverez plus d'informations sur ce post : AC's CR/R tools for SPDevs Updated: v1.1

Pour finir, j'aime beaucoup cet outil qui me laisse avoir une grande liberté dans la création et la composition de mes projets SharePoint tout en m'apportant le petit plus, qui fait toute la différence en terme d'intégration.

WSPBuilder

Le moins que l'on puise dire est que Carsten Keutmann (créateur de WSPBuilder et de SharePoint Manager) aura été utile à la communauté SharePoint en 2007 !

En créant et améliorant tout à long de l'année WSPBuilder, Carsten aura résolu à lui seul une des plus grandes problématiques qu'un développeur SharePoint peut rencontrer lors d'une mission : Le packaging d'un projet SharePoint en un fichier wsp.

Pour illustrer mes propos, reprenons l'exemple de la webpart HelloWorld :

Utiliser une feature pour déployer la webpart dans SharePoint est une bonne habitude à prendre qui vous permettra d'activer la fonctionnalité simplement sur vos sites SharePoint.

Mais si vous voulez déployez votre webpart, il va falloir déployer la DLL (dans le GAC ou dans le BIN) ainsi que les fichiers XML (dans le repertoire Features) de chacun de vos WebFronts.

Pour un peu que vous en ayez plusieurs et que vous rajoutiez à votre webpart ou à votre feature quelques images, css, etc... Le déploiement se révélera vite très compliqué.

Mais pas de panique, l'équipe SharePoint a pensé à tout et vous permet de rassembler tout les composants que vous avez besoin en un seul fichier et de les déployer automatiquement via l'utilisation d'un package appelé "Solution", ayant communément une extension de fichier en .wsp.

Pour générer ce fichier, vous aller avoir besoin de créer deux fichiers :

  • manifest.xml

manifest

C'est ce fichier qui va décrire à SharePoint ce qu'il doit faire des autres fichiers présents dans la solution. Le fichier "solution" n'est en fait qu'un fichier .cab renommé en .wsp qui référence les fichiers présents dans le fichier .ddf

  • makecab.ddf (le nom du fichier n'est pas important)

ddf

Bref, cela peut se révéler assez compliqué de créer tout ça à la main quand on commence à avoir un peu plus de fichiers...

Pour plus de détails, je vous encourage à lire cet excellent article de Ted Pattison sur la création d'un package SharePoint : Creating a Solution Package in Windows SharePoint Services 3.0

Vous l'aurez sans doute compris, c'est au niveau de la phase de création des fichiers DDF, XMl, et WSP que WSPBuilder intervient. Il suffit de lui préciser où vous souhaitez déployer vos fichiers (GAC, BIN, 12\Templates\Features, etc...) :

WSPFolder

Il ne vous reste plus qu'a lancer l'utilitaire WSPBuilder.exe via une ligne de commande ...

WSPConsole

... pour qu'il vous génère automatiquement le fichier WSP qui vous intéresse :

WSPSolution

Il ne vous restera plus qu'à le déployer sur votre environnement SharePoint (stsadm -o addsolution, déploysolution, activatefeature, etc..) et le tour est joué !

On notera que depuis peu, WSPBuilder s'intègre à Visual Studio 2005/2008 avec l'ajout d'un nouveau menu WSPBuilder dans le menu contextuel de projet :

WSPMenuContextuel

Ce menu vous permettra de générer directement votre fichier wsp, de le déployer, de le désinstaller, de le mettre à jour, d'en faire une copie "quick and dirty" vers le repertoire 12 local et finalement de recycler les pools d'applications (ce qui est bien plus rapide qu'un IISRESET).

Mais il y a aussi l'arrivée de nouveaux templates de projets avec une arborescence de répertoires pré construite, bien pratique :

WSPProject

5 

Pour résumer, WPSBuilder est devenu en quelques mois un vrai référence en terme de génération de package SharePoint. De plus il se couple très bien avec les extensions CodeRush pour SharePoint et permet de générer la solution qui vous correspond. A mes yeux, ces deux outils peuvent être une alternative tout à fait valable sur VisualStudio 2008 en attendant les VseWSS 1.2 qui devraient sortir en Juin 2008.

<Philippe/>

SharePoint 2007 : Community Kit for SharePoint, Sortie de la version 2.0 du Enhanced Blog Edition

Si vous souhaitez améliorer les fonctionnalités et le look and feel des sites de blog dans SharePoint alors ce projet Codeplex est fait pour vous !

Voilà quelques exemples de ce que vous pouvez avoir en standard :