SharePoint 2007 : Projet Codeplex > SharePointOfView

[English version @ http://codeplex.com/SharePointOfView]

Notre projet SharePointOfView vient d'ouvrir ses portes sur Codeplex.

Le but de ce projet est de regrouper un ensemble de fonctionnalités dans le but simplifier le développement avec SharePoint.

L'idée est de partager sur Codeplex, les bouts de code utilitaires que nous (Gat, Julien, Seb, Adrien et moi) utilisons chaque jour lorsque nous développons sous SharePoint.

Vous pourrez retrouver en détails les fonctionnalités inclues dans ce projet sur les blogs respectifs des contributeurs.

La release actuelle inclut les méthodes suivantes:
  • SharePointOfView.Diagnostics
    • ULS : Ecrit dans le log SharePoint. ref : MSDN :Trace Log Example
    • SPEventLog: Ecrit dans l'Event Log dans la source 'Windows SharePoint Services 3'
  • SharePointOfView.EventReceivers
    • WebConfigFeatureReceiver : SPFeatureReceiver qui permet des modifications simplifiée du web.config via a XML file.
  • SharePointOfView.ExpressionBuilders
    • ResourcesExpressionBuilder : Vous permet d'écrire ce genre de chose "<asp:Label id="lbHelloWorld" runat="server" Text="<%$ SPResources:res,HelloWorld %>" />" directement dans la partie ASPX de votre page SharePoint
  • SharePointOfView.ExtensionMethods
    • SovTryGet<T> : Essaye de récupérer l'élément dans la SPBaseCollection.
    • SovDeleteUploadedFiles : Supprime les fichiers Uploadés via la section Module.(ref. Robert L. Bogue’s code | http://www.thorprojects.com/blog)
    • SovDeleteItems : Supprime les éléments de la liste en utilisant ProcessBatchData (plus rapide) 
    • SovAddItems : Ajout des éléments à la liste en utilisant ProcessBatchData (plus rapide)
  • SharePointOfView.Utilities
    • Localization : Récupère la chaine à partir de la cléf, du fichier de ressource et de la langue choisie
    • Version : Pemet de savoir si MOSS est installé ou pas 
    • WebConfigModification : Ajout ou Supprime une modification de configuration à un web.config
  • SharePointOfView.WebControls
    • WebPartBase : Web Part Base avec une gestion "fun" des exception
    • XslTransformWebPart : Web Part Base qui applique un XSL Transform à un fichier XML

Vous trouverez un autre projet dans la solution SharePointOfView nommé SharePointOfView.Samples. Il contient de nombreux exemples qui vous permettre de mieux comprendre l'intérêt de ces méthodes.

La release actuelle de SharePointOfView.Samples inclut les features suivantes :

  • SOVASPNETAjaxConfig
    • Ajoute le support ASP.Net Ajax à l'application Web
  • SOVExtensionMethods
    • sur la Feature Activation : Uploade 4 'Hello World' Web Parts, Crée une Custom List and Insère 50 Items "Random".
    • sur la Feature Deactivation : Supprime tout les éléments de la liste, Supprime la liste and Supprime les Web Parts de la Gallery de Web Parts
  • SOVWebControls
    • sur la Feature Activation : Uploade WebPartBase and XslTransformWebPart
    • sur la Feature Deactivation : Supprime les Web Parts de la Gallery de Web Parts

L'installation de ce projet se fait très simplement :

Ce sample necessite d'avoir installé :
  • ASP.Net Ajax
  • WSS SP1

Bien évidemment si vous avez des idées, des suggestions ou tout simplement l'envie de participer à ce projet, n'hésitez pas à nous contacter !

<Philippe/>

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

En parcourant les mises à jours des projets Codeplex sur SharePoint, je tombe ce matin sur la mise à jour d'un outil dont j'étais sur de vous avoir déjà parlé : SharePoint Solution Installer. Mais en fait, j'avais oublié de finir cette suite de post sur les outils de création et de déploiement (ici et ). Désolé.

Comme vous le savez sans doute (mais on ne le répète jamais assez), tout développement dans SharePoint se fait via Feature. Et tout déploiement dans SharePoint se fait via Solutions.

Une solution n'est rien d'autre qu'un fichier CAB renommé en .WSP. Ce fichier comprend tout les fichiers (dll, aspx, etc...) nécessaire au bon fonctionnement de vos nouvelles fonctionnalités ainsi qu'un fichier manifest.xml et ddf qui permettra à SharePoint de savoir quoi en faire.

Voici quelques liens provenant de mon del.icio.us concernant la génération de solution :

Autant, nous avons déjà vu ensemble comment un développeur peut générer un fichier .WSP (cf. liens ci-dessus) autant parfois le déploiement n'est pas forcément des plus aisé (via stsadm par exemple), ou bien c'est pas forcement évident d'expliquer à un administrateur n'ayant jamais utilisé SharePoint comment déployer une solution sur son environnement...

Et bien cette période est révolue avec l'utilisation de SSI (SharePoint Solution Installer).

Voilà le genre de choses que vous allez dorénavant pouvoir faire :

SharePoint Solution Installer

Les fonctionnalités en pratique : Ajout, Déploiement, Mise à jour, Retirer , Supprimer une Solution, Activation de Feature (Scope : Farm, SiteCollection)

Ainsi qu'un ensemble de vérifications comme :

  • WSS installé
  • MOSS installé
  • Utilisateur a les permissions requises
  • Base de donnée SharePoint en ligne
  • Service WSS Administration démarré
  • Service WSS Timer démarré

Il est possible d'afficher une EULA et de configurer la bannière de l'application ainsi que le titre, le logo et la documentation.

Vous pouvez aussi (une fois l'installation terminée, afficher un lien vers la configuration de vos développements.

Au final, ce que j'aime bien c'est qu'en modifiant le logo, le nom de la solution et tout le reste, on obtient une "sorte" de packaging très pro et très intuitif. Le tout via l'utilisation d'un fichier de config:

<configuration>

  <appSettings>

    <add key="BannerImage" value="Default"/>

    <add key="LogoImage" value="Default"/>

    <add key="EULA" value="EULA.rtf"/>

    <add key="SolutionId" value="44906C46-D7C1-4a14-A7D2-87394D9FC7E3"/>

    <add key="SolutionFile" value="yoursolution.wsp"/>

    <add key="SolutionTitle" value="Enter Product Title Here"/>

    <add key="SolutionVersion" value="1.0.0.0"/>

    <add key="FeatureScope" value="Farm"/>

    <add key="FeatureId" value="A69D3FDA-142A-4d2c-BA6D-446CE01FF1C2"/>

    <add key="UpgradeDescription" value="Upgrades {SolutionTitle} on all frontend web servers in the SharePoint farm. "/>

    <add key="RequireDeploymentToCentralAdminWebApplication" value="true"/>

    <add key="RequireDeploymentToAllContentWebApplications" value="false"/>

    <add key="DefaultDeployToSRP" value="false"/>

    <add key="RequireMOSS"value="true"/>

    <add key="SSPRelativeConfigLink" value="/_layouts/MyFeature/Config.aspx"/>

    <add key="DocumentationUrl" value="http://www.mycompany.com/MyFeatureDoc.aspx"/>

  </appSettings>

</configuration>

Touareg

Et bien sur, comme c'est un projet Codeplex, les sources sont disponibles :)

PS : plus d'infos sur Touareg : http://www.touareg-project.com/Default.aspx

<Philippe/>

SharePoint 2007 : Extension Method (DeleteUploadedFiles)

Parmi les trucs que je dois recoder à longueur de journée et dont je voudrais bien me passer : Faire le nettoyage (Supprimer)  des éléments uploadés par une feature.

Pour rappel, si je souhaite uploader plusieurs Web Part dans SharePoint, je vais déclarer la feature suivante (d'exemple) :

ArborescenceFeature

Feature.xml : (NB : Les attributs ReceiverAssembly et ReceiverClass ne sont pas necessaire pour une feature de base)

<?xml version="1.0" encoding="utf-8" ?>

<Feature xmlns="http://schemas.microsoft.com/sharepoint/"

        Id="C3C567EA-AC7B-402F-A328-F1AF9F9849F5"

        Title="Hello World WP"

        Description="Affiche une WebPart qui 'HelloWorld'"

        Scope="Site"

        Hidden="False"

        Version="1.0.0.0"

        ReceiverAssembly="HelloWorld, Version=1.0.0.0, Culture=neutral, PublicKeyToken=129475d183be15e5"

        ReceiverClass="HelloWorld.FeatureReceiver">

 

  <ElementManifests>

    <ElementManifest Location="elements.xml" />

  </ElementManifests>

 

</Feature>

Elements.xml :

<?xml version="1.0" encoding="utf-8" ?>

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">

  <Module Url="_catalogs/wp"

          Path="WP"

          RootWebOnly="TRUE">

    <File Url="EasyWebPart1.webpart"

          Type="GhostableInLibrary">

      <Property Name="Group" Value="Hello World" />

      <Property Name="Title" Value="HelloWorld 1" />

    </File>

    <File Url="EasyWebPart2.webpart"

      Type="GhostableInLibrary">

      <Property Name="Group" Value="Hello World" />

      <Property Name="Title" Value="HelloWorld 2" />

    </File>

  </Module>

  <Module Url="_catalogs/wp"

        Path="WP"

        RootWebOnly="TRUE">

    <File Url="EasyWebPart3.webpart"

          Type="GhostableInLibrary">

      <Property Name="Group" Value="Hello World" />

      <Property Name="Title" Value="HelloWorld 3" />

    </File>

    <File Url="EasyWebPart4.webpart"

      Type="GhostableInLibrary">

      <Property Name="Group" Value="Hello World" />

      <Property Name="Title" Value="HelloWorld 4" />

    </File>

  </Module>

</Elements>

En pratique, je crée deux sections "modules" qui uploadent chacune 2 webpart dans le répertoire "_catalog/wp" de ma collection de site. Ce répertoire étant au final l'endroit où sont stockées les Web Part dans SharePoint.

ListedeWebpart

Maintenant si j'active cette feature, je vais bien avoir mes 4 Web Part uploadées où il faut :

WebPartUploaded

Mais si je désactive la feature, les fichiers sont toujours là...

En pratique ce n'est pas toujours une mauvaise chose mais dans certains cas (souvent), on peut vouloir nettoyer tout ça via un FeatureReceiver sur la désactivation de la feature. Et ca peut vite devenir rébarbatif quand on upload tout les 4 matins des Web Parts.

D'où la création d'une méthode d'extension pour me simplifier tout ça :)

En pratique, voilà comment je fais :

Dans mon Feature Receiver, je fais simplement appel à la méthode DeleteUploadedItems directement à partir du SPFeatureReceiverProperties qui m'est fourni par la méthode FeatureDeactivating.

class FeatureReceiver : SPFeatureReceiver

{

    #region NotImplemented

    public override void FeatureActivated(SPFeatureReceiverProperties properties)

    {

        //throw new NotImplementedException();

    }

 

    public override void FeatureInstalled(SPFeatureReceiverProperties properties)

    {

        //throw new NotImplementedException();

    }

 

    public override void FeatureUninstalling(SPFeatureReceiverProperties properties)

    {

        //throw new NotImplementedException();

    }

    #endregion

 

    /// <summary>

    /// Occurs when a Feature is deactivated.

    /// </summary>

    /// <param name="properties">An <see cref="T:Microsoft.SharePoint.SPFeatureReceiverProperties"></see> object that represents the properties of the event.</param>

    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

    {

        properties.DeleteUploadedFiles();

    }

}

et voici le code de la méthode qui nous intéresse au final :

/// <summary>

/// Deletes the uploaded files. (Inspired from a Robert L. Bogue’s code | http://www.thorprojects.com/blog)

/// </summary>

/// <param name="properties">The properties.</param>

public static void DeleteUploadedFiles(this SPFeatureReceiverProperties properties)

{

    SPWeb web = null;

    switch (properties.Definition.Scope)

    {

        case SPFeatureScope.Site:

            SPSite site = (SPSite)properties.Feature.Parent;

            web = site.RootWeb;

            break;

        case SPFeatureScope.Web:

            web = (SPWeb)properties.Feature.Parent;

            break;

        default:

            return;

    }

 

    foreach (SPElementDefinition element in properties.Definition.GetElementDefinitions(CultureInfo.CurrentCulture))

    {

        if (element.ElementType == "Module")

        {

            string fileUrl = string.Empty;

 

            XmlNode moduleNode = element.XmlDefinition;

            if (moduleNode.Attributes["Url"] != null)

                fileUrl = moduleNode.Attributes["Url"].Value + '/';

 

            XmlNodeList fileNodes = moduleNode.SelectNodes("*[local-name()='File']");

 

            if (fileNodes != null)

            {

                foreach (XmlNode fileNode in fileNodes)

                {

                    string fullFileUrl = SPUrlUtility.CombineUrl(fileUrl, fileNode.Attributes["Url"].Value);

                    SPFile file = web.GetFile(fullFileUrl);

 

                    if (file != null && file.Exists)

                        file.Delete();

                }

            }

        }

    }

}

On récupère les SPElementDefinition, vérifie qu'il s'agit d'un type "Module", récupère le dossier où tout est uploadé puis le chemin complet pour accèder au fichier. Si le fichier existe, on le supprime.

PS : Ce bout de code est librement inspiré d'un précédent travail effectué par Robert L. Bogue (Blog: http://www.thorprojects.com/blog, Auteur du SharePoint Shepherd's Guide for End Users http://www.sharepointshepherd.com/)

Comme toujours, si vous avez des idées ou des corrections à apporter à ce code, n’hésitez pas à m’en faire part.

<Philippe/>

[Off Topic] Update Del.icio.us, Twitter

Posté le lundi 9 juin 2008 12:18 par phil :: 0 commentaire(s)
Classé sous

Pour ceux qui me suivaient sur mon précédent account del.icio.us, j'ai décidé de changer d'account (le pseudo ne me semblait pas vraiment approprié...). Vous pourrez désormais regarder ce que je surveille sur SharePoint à cette URL : http://del.icio.us/philippesentenac/sharepoint. Tout le contenu n'est pas encore migré, le serveur del.icio.us semble tomber en rade quotidiennement.

J'en ai profité pour créer/tester twitter, vous pourrez me suivre dorénavant sur www.twitter.com/orijin.

<Philippe/>

SharePoint 2007 : Extension Method (AddItems)

Lors des précédent billets sur les extensions de méthode, je vous ai parlé d'un manière plus intuitive de récupèrer une SPList (mais potentiellement SPWeb, SPUser, etc...), je vous ai aussi montrer comment gagner énormément de temps lors de la suppression d'élements dans vos liste et finalement, pour boucler la boucle, je vais vous montrer aujourd'hui une méthode qui vous permet d'ajouter simplement des éléments dans une liste en évitant la méthode classique qui peut sembler rébarbative:

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

{

    using (SPWeb web = site.RootWeb)

    {

        SPList listAnnonces;

        Stopwatch stopWatch = new Stopwatch();

 

        //So easy to get a SPList like that.

        if (web.Lists.TryGet(STR_Annonces, out listAnnonces))

        {

            Console.WriteLine("List : {0} Add via Classic Method\r\n\tBefore \tNB Items : {1}", STR_Annonces, listAnnonces.ItemCount);

            Random rnd = new Random();

 

            SPListItemCollection listAnnoncesItems = listAnnonces.Items;

            //Generate a paragraph of Lipsum from http://code.google.com/p/nlipsum/

            string bodyContent = LipsumGenerator.Generate(1);

            stopWatch.Start();

 

            for (int i = 0; i < 100; i++)

            {

                SPListItem item = listAnnoncesItems.Add();

                item["Title"] = rnd.Next();

                item["Body"] = bodyContent;

                item["Expires"] = DateTime.Now;

                item.Update();

            }

            listAnnonces.Update();

 

            stopWatch.Stop();

 

            Console.WriteLine("\tAfter \tNB Items : {1}\tElapsed : {2} Msec",

                STR_Annonces,

                listAnnonces.ItemCount,

                stopWatch.ElapsedMilliseconds);

 

            stopWatch.Reset();

...

Et encore ici, je triche un peu en utilisant ma méthode d'extension qui me permet de simplifier l'accès à la liste.

Maintenant si je compare en utilisant l'extension de méthode AddItems sur une SPList:

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

{

    using (SPWeb web = site.RootWeb)

    {

        SPList listAnnonces;

        Stopwatch stopWatch = new Stopwatch();

 

        //So easy to get a SPList like that.

        if (web.Lists.TryGet(STR_Annonces, out listAnnonces))

        {

            Console.WriteLine("List : {0} Add via Extension Method\r\n\tBefore \tNB Items : {1}", STR_Annonces, listAnnonces.ItemCount);

 

            //Create the Data you will insert in each Items

            Dictionary<string, string> metadata = new Dictionary<string, string>();

            metadata.Add("Title", null);

            //Generate a paragraph of Lipsum from http://code.google.com/p/nlipsum/

            metadata.Add("Body", LipsumGenerator.Generate(1));

            string validDateTimeFormat = SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now);

            // We need to insert a valid dateTime with a specific format : 2008-06-01T14:02:08Z

            metadata.Add("Expires", validDateTimeFormat);

 

            stopWatch.Start();

            listAnnonces.AddItems(100, metadata, true);

            stopWatch.Stop();

 

            Console.WriteLine("\tAfter \tNB Items : {1}\tElapsed : {2} Msec", STR_Annonces,

                listAnnonces.ItemCount,

                stopWatch.ElapsedMilliseconds);

        }

 

         //Another Example with a different format (URL)

        if (web.Lists.TryGet(STR_Liens, out listAnnonces))

        {

            Console.WriteLine("List : {0}, Number of Items  : {1}", STR_Liens, listAnnonces.ItemCount);

 

            Dictionary<string, string> metadata = new Dictionary<string, string>();

            metadata.Add("URL", http://localhost, Home);

            metadata.Add("Comments", LipsumGenerator.Generate(1));

 

            listAnnonces.AddItems(10, metadata, true);

 

            Console.WriteLine("List : {0}, Number of Items  : {1}", STR_Liens, listAnnonces.ItemCount);

        }

    }

}

Au final, ces appels nous donne en sortie la création de 100 éléments chacun, voyons la différence en terme de rapidité.

diff_classic_and_extension

Encore une fois, c'est l'utilisation de ProcessBatchData qui nous permet d'avoir cette différence de performance. L'utilisation en elle-même n'est pas des plus aisée, d'où l'intérêt de l'encapsuler dans cette extension de méthode :

/// <summary>

/// Adds Item to the selected List, will use the metadata to insert data into Columns

/// Will throw an SPException if an error occurs or If Metadata is null

/// </summary>

/// <param name="list">The list.</param>

/// <param name="nbItems">The Number of items to create</param>

/// <param name="metadata">The metadata used to insert data into Items.</param>

public static void AddItems(this SPList list, int nbItems, Dictionary<string, string> metadata, bool forceUpdate)

{

    if (metadata == null)

        throw new SPException("AddItems : Metadata can't be null");

 

    // Adding 0 items...

    if (nbItems == 0)

        return;

 

    StringBuilder sbAdd = new StringBuilder(100 * nbItems);

    sbAdd.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><Batch OnError=\"Return\">");

    Guid listGuid = list.ID;

    for (int i = 0; i < nbItems; i++)

    {

        sbAdd.AppendFormat("<Method ID=\"{0},Save\"><SetList>{1}</SetList><SetVar Name=\"ID\">New</SetVar><SetVar Name=\"Cmd\">Save</SetVar>", i, listGuid);

        foreach (KeyValuePair<string, string> pair in metadata)

        {

            string value = pair.Value;

            //Just in case, i wan't a field with pseudo random content, should propably improve this.

            if (value == null)

                value = rnd.Next().ToString();

            sbAdd.AppendFormat("<SetVar Name=\"urn:schemas-microsoft-com:office:office#{0}\">{1}</SetVar>", pair.Key, value);

        }

        sbAdd.Append("</Method>");

    }

    sbAdd.Append("</Batch>");

 

    SPWeb oListParentWeb = list.ParentWeb;

    string batchResult = oListParentWeb.ProcessBatchData(sbAdd.ToString());

    //Dispose !!! http://blogs.msdn.com/rogerla/archive/2008/02/12/sharepoint-2007-and-wss-3-0-dispose-patterns-by-example.aspx

    oListParentWeb.Dispose();

 

    if (forceUpdate)

        list.Update();

 

    string errorMessage = ResultFromBatchCommand(batchResult);

    if (errorMessage != String.Empty)

        throw new SPException(errorMessage);

}

Si vous avez d'autre idées de méthodes ou d'optimisations, n'hésitez à pas à laisser un commentaire.

<Philippe/>

SharePoint 2007 : Installer WSS 3.0 SP1 sur Vista x64/x86

Et non ce n'est pas une blague !

Si vous êtes comme moi, vous êtes toujours à la recherche de LA solution pour avoir un environnement de développement le plus performant possible.

Et bien, je viens de tomber sur une petite perle ce matin :

Il semblerait que Bamboo Solutions ai developper une application pour installer WSS 3.0 SP1 sur vista (X64 et X86). Plus besoin de VPC/VMWare ni Hyper-V !!

Bien évidemment, ce produit est encore en béta, vous pouvez le télécharger et laisser vos commentaires sur ce forum.

Il y a encore des limitations :

  • Il n'installe pas SQLExpress si vous ne l'avez pas (super....)
  • Vous devez sélectionner le menu "Advanced Option" pendant l'install
  • Il faut manuellement configurer IIS7 avec les bonnes options (cf images plus bas)
  • Votre station de travail doit être dans un domaine.

C'est partie pour la procédure d'install (en Anglais) :  http://community.bamboosolutions.com/blogs/bambooteamblog/archive/2008/05/21/how-to-install-windows-sharepoint-services-3-0-sp1-on-vista-x64-x86.aspx

First download the installation helper and the correct version of WSS with SP1.

Windows SharePoint Services 3.0 with Service Pack 1

Windows SharePoint Services 3.0 x64 with Service Pack 1

Go here to download our Installtion Helper file.  Now install the setup helper (WssVista.msi)

You will see an UAC prompt before the install continues, it looks “scarier” than usual since our msi is not signed

If you trust us (and you should) press Allow to finish the installation.

Once the install has completed you will find the SetupLauncher.exe in the install location you selected. If you didn’t change the default option you will see it under Program Files\WssOnVista\Setup

Configuring IIS7

Before we go any further we need to make sure IIS7 is installed with all required options .

Go to Control Panel and click Programs.

Under Program and Features click Turn Windows features on or off.

Under Windows Features select Web Management Tools and World Wide Web Services. Check at least the following options and choose OK.

Wait until Windows has configured all options.

Installing Windows SharePoint Services 3.0 SP1 on Vista.

After completing the above steps it’s time for the interesting part. Locate SetupLauncher.exe and start it. You will once again see an UAC prompt select Allow.

First the package will be extracted.

After the files have been extracted the setup is started.

The current version only supports the advanced installation option so select that one.

Select Web Front End when asked about Server Type. The database will be created later.

Sit back and relax while SharePoint is being installed, you are running Vista remember ;)

Hopefully you will see the following screen at the end of the installation. If you would get an error during the installation step try to run a Repair.

Leave the checkbox checked and click Close to run the Configuration Wizard.

image

At the second screen select the option to create a new server farm.

image

Specify your database server and account information.

image

image
image

Let the Configuration Wizard do it's work.

image

And you should end up with this screen, congratulations!

image

image

The final result is WSS running on Vista, Enjoy!

/Jonas

Note: Remember that this is a "beta" product from Bamboo.  Do not use it for any production work, as well as the usual "backup your system before install this program".  Additional discussion about this tool can be found in this forum.

Me manque plus qu'à trouver un volontaire pour installer ça sur sa bécane... Gniark gniark.

<Philippe/>

SharePoint 2007 : Enquête Patterns & Practices

Glenn Block, le Technical Product Planner du groupe Patterns & Practices , a mis en place une enquête afin d'obtenir votre feedback sur les point de difficultés et vos besoins sur SharePoint.

On connait tous la qualité de leur contenu, c'est pourquoi je vous encourage vivement à répondre à cette enquête

Ci dessous l'annonce sur son blog :

image

First let me start off by allaying all your fears, "No it's not another factory". :-)

For a while we've been hearing a lot of requests from customers for patterns & practices to deliver guidance on SharePoint. For several weeks now we've been exploring this space, and evaluating where we might be able to deliver value.

With the new guidance, we want to focus on a specific set of scenarios which SharePoint is appropriate for. We then want to focus on what solution is appropriate for addressing those scenarios and why.

If you've been developing SharePoint solutions, then we need your help. Please take the following survey and let us know what your pain points are, where do YOU see the most need for guidance?

<Philippe/>

SharePoint 2007 : Extension Method (DeleteAllItems)

Après vous avoir parlé de ce que l'on pouvait faire avec les extensions de méthode et un peu de "réflection", j'aimerais vous montrer aujourd'hui une autre combinaison très intéressante :

Les extensions de méthode et ProcessBatchData : Voici un exemple avec une extension de méthode qui supprime tout les éléments d'une liste ou d'un bibliothèque de document.

Ci-dessous, je compare deux méthodes, la suppression classique d'éléments dans une liste et la suppression en utilisant l'extension de méthode DeleteAllItems.

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

    {

        using (SPWeb sPWeb = sPSite.RootWeb)

        {

            SPList sPList;

            Stopwatch stopWatch = new Stopwatch();

 

            if (sPWeb.Lists.TryGet(STR_Annonces, out sPList))

            {

                Console.WriteLine("List : {0} Delete via Foreach\r\n\tBefore \tNB Items : {1}", STR_Annonces, sPList.ItemCount);

                stopWatch.Start();

                List<int> listId = new List<int>();

 

                foreach (SPListItem item in sPList.Items)

                    listId.Add(item.ID);

                foreach (int itemId in listId)

                    sPList.Items.DeleteItemById(itemId);

 

                sPList.Update();

                stopWatch.Stop();

                Console.WriteLine("\tAfter \tNB Items : {1}\tElapsed : {2} Msec",

                    STR_Annonces,

                    sPList.ItemCount,

                    stopWatch.ElapsedMilliseconds);

                stopWatch.Reset();

            }

 

            #region Rajout d'Elements à la liste STR_Annonces

 

            #endregion

 

            if (sPWeb.Lists.TryGet(STR_Annonces, out sPList))

            {

                Console.WriteLine("List : {0} Delete via Extension Method\r\n\tBefore \tNB Items : {1}", STR_Annonces, sPList.ItemCount);

                stopWatch.Start();

                sPList.DeleteAllItems(true, null);

                stopWatch.Stop();

                Console.WriteLine("\tAfter \tNB Items : {1}\tElapsed : {2} Msec",

                    STR_Annonces,

                    sPList.ItemCount,

                    stopWatch.ElapsedMilliseconds);

                stopWatch.Reset();

            }

        }

    }

En terme de performance, c'est assez impressionnant !

image

Voilà la méthode qui permet de réaliser ce petit tour de magie.

L'idée est d'utiliser ProcessBatchData pour effectuer sur un ensemble d'éléments la même action (ici, un Delete) en une seule fois. l'avantage de la méthode ProcessBatchData est qu'elle est extrêmement rapide (notamment car elle nécessite moins de traffics avec le serveur SQL).

Cependant, cette méthode n'est pas forcément des plus intuitives à utiliser et j'ai trouver intéressant de l'encapsuler dans une extension de méthode. L'ensemble de la requête est basé sur du CAML et l'utilisation de mot clef (SetList, Set Var, etc...)

PS : Dans les exemples ci-dessus, je n'utilise pas le paramètre metadata, j'en expliquerais l'utilité par la suite.

    /// <summary>

    /// Delete all the items specified via the metadata dictionnary (ID, FileUrl), FileUrl has to be null for SPList

    /// If metadata is null, it will delete every items in the list

    /// Use SPWeb.ProcessBatchData to execute the delete command

    /// cf : http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spweb.processbatchdata.aspx

    /// </summary>

    /// <param name="oList">The List</param>

    /// <param name="forceUpdate">Will force the list update</param>