I. Introduction

La WebPart que nous allons créer ici, va permettre de se familiariser avec le langage CAML. Ce langage est très utilisé dans SharePoint 2007, il est au coeur même du système. On le trouve absolument partout, y compris dans les WebPart. Il permet d'effectuer des requêtes afin de récupérer différentes informations contenues dans votre site. Nous allons donc essayer de voir l'ensemble des fonctionnalités indispensables à connaitre pour créer des WebPart permettant de faire des recherches. Ce n'est pas un cours sur le langage CAML qui est proposé ici, mais une introduction à sont utilisation dans avec les WebPart, nous ne verrons donc que certains aspect de ce langage.

J'ai volontairement détaillé au maximum les différentes étapes, car toutes les personnes utilisant SharePoint ne sont pas des développeurs, hors tout utilisateur ou administrateur, peut être obligé de créer une WebPart pour un besoin spécifique à son environnement de travail.

II. Contexte

Pour le bon fonctionnement de notre WebPart, nous avons besoins d'une custom list, ou d'une bibliothèque de formulaire ainsi que d'un projet Visual Studio de type WSPBuilder. Si vous avez déjà cette configuration ou si vous savez comment la mettre en place sans difficulté, je vous invite à passer directement au chapitre 4 sans plus attendre.

Ce dont vous avez besoin pour suivre cet article :

  • Windows server 2003 R2 ou version ultérieure
  • Microsoft Office SharePoint ( WSS ou MOSS )
  • Microsoft Visual Studio 2008 ou version ultérieure
  • WSPBuilder (téléchargement ici )

III. Mise en place de l'environnement

III-A. Création du projet

Pour commencer nous allons créer un nouveau projet dans Visual Studio, comme ceci :

Image non disponible

Nous choisissons un projet de type WSPBuilder, avec pour template "WSPBuilder Project". Nous nommerons ce projet "CAMLWebPart".

Image non disponible

Nous devons maintenant ajouter notre WebPart à notre solution, pour cela il faut se placer dans la fenêtre "Solution explorer", sélectionner notre projet, puis faire un click droit, "Add" puis "new item...".

Image non disponible

Maintenant nous allons ajouter la WebPart que l'on nommera "CAML" :

Image non disponible

Nous choisirons la "scope" site . Libre à vous de placer ce que vous voulez dans le titre et la description de la WebPart.

Image non disponible

Une fois cette étape terminée, nous allons pouvoir commencer à visualiser ce que les assistants ont fait pour nous.

Tout d'abord, dans la fenêtre "Solution explorer", on constate qu'il existe plusieurs dossiers.

Image non disponible

Ces différents dossiers correspondent à la hiérarchie de Microsoft Office Sharepoint. Plus particulièrement à la hiérarchie du dossier système ou toutes les informations brutes de Sharepoint sont stockées, à savoir, tout ce qui n'est pas directement dans la base de données SQL Server.

Si vous êtes curieux et souhaitez en apprendre d'avantage, je vous invite à aller jeter un coup d'oeil directement dans ce dossier qui se trouve dans " C:\Program Files\Common Files\Microsoft Shared\web server extensions\12 ".

Dans notre dossier "CAML", il existe trois fichiers :

CAML.webpart

Ici nous retrouvons la définition de la WebPart, les informations basiques qui seront fournis à l'utilisateur lors de sa mise en place.

  • elements.xml Ici nous retrouvons les données relatives à l'emplacement de la WebPart dans le menu de SharePoint, ici on constate notamment que la WebPart est par défaut dans un groupe appelé "MyGroup".
  • feature.xml Ici nous retrouvons les données qui correspondent au versioning ainsi qu'à l'identification de la feature. On y trouve notamment l'Id de la feature mais aussi le titre, la description la version etc... Ces données correspondent aux informations que l'on retrouvera dans la liste des features présentent dans notre collection de site SharePoint.

Un autre dossier à également été créé, il s'agit du dossier "WebPartCode", celui ci contient le code c# de notre WebPart, il est donc pour le moment presque vide.

III-B. Création d'une liste SharePoint de référence

Comme je vous l'ai précisé au début de cet article, le CAML est un langage intégré dans SharePoint 2007 qui nous permet de rechercher des informations contenues dans notre site.

Mais pour ce faire, faut-il encore avoir des données à aller chercher. Nous allons donc créer une liste dans SharePoint afin d'avoir des données à aller chercher.

Je suppose que vous savez comment créer une liste, je ne vais donc pas détailler cette partie, je vais juste vous montrer la liste que je vais utiliser pour l'exemple afin de vous permettre de mieux comprendre la suite. Voici donc la liste que j'ai appelée "CamlSearch" :

Image non disponible
Image non disponible

Comme vous pouvez le constater une liste très simple, avec uniquement trois champs ajoutés, à savoir "Nom", "Prénom" et "Date".

III-C. Activation des erreurs ASP

SharePoint est un outil destiné à un large panel d'utilisation et d'utilisateurs. Afin que votre site paraissent le mieux possible, SharePoint utilise ce que l'on appel les "custom errors", ce qui veux dire que si une erreur intervient lors d'une manipulation, un gentil message apparait afin de vous informer que l'opération désirée n'est pas possible et qu'il faut contacter votre administrateur afin d'obtenir d'avantages de renseignements. Etant des développeurs, comment faire pour savoir d'où provient notre erreur si nous ne pouvons pas visualiser son contenu? Pour éviter ce désagrément et avoir le vrai message d'erreur, il faut modifier le fichier "web.config" de votre site web. Celui-ci se trouve dans le dossier "C:\ Inetpub\wwwroot\wss\VirtualDirectories\Port_Number ", le "Port_Number" correspond bien entendu au numéro du port que vous avez déterminé lors de la création de votre site. Il existe deux balises à modifier : (je vous invite à effectuer une recherche afin de les trouver)

  • <customErrors mode="On"> : Cette balise permet à SharePoint d'utiliser ces propres messages d'erreur, il faut donc la changer pour mettre "Off".
  • <CallStack="false"> : Cette balise va vous permettre d'afficher la pile d'appel de l'application, elle peut vous permettre d'obtenir d'avantage d'information, il faut donc la modifier pour mettre "true".


Parfait nous allons pouvoir commencer à coder.

IV. Code de la WebPart

IV-A. La Base

Comme je viens de vous le préciser, le fichier contenant le code c# de notre WebPart n'est pas complètement vide. En effet WSPBuilder a déjà rempli ce fichier avec quelques fonctions, mais nous n'aurons pas besoin de tout cela, nous allons donc nettoyer ce fichier, voici le contenu du fichier que vous devez obtenir :

Nous avons ici le strict minimum dont nous avons besoin, à savoir le constructeur et la méthode "CreateChildControls" qui n'est autre que la méthode de création de nos différents composants.


En premier lieu il est important de lister les différents éléments dont on va avoir besoin.

  • Le nom de la liste : CamlSearch
  • Le nom de la colonne sur laquelle va se porter notre recherche : Nom
  • Le type de l'élément de la recherche : en fonction des tests
  • La valeur que l'on recherche : en fonction des tests
  • Afficher le résultat

Nous pouvons désormais coder.


Nous allons commencer par créer un Label, celui-ci va nous permettre d'afficher le résultat de notre requête dans la WebPart.

 
Sélectionnez
public class CAML : Microsoft.SharePoint.WebPartPages.WebPart
{
    private Label lbl_Result;

Parfait maintenant nous allons créer un méthode, que nous nommerons "ExecuteQuery", qui comme sont nom l'indique va nous permettre d'exécuter la requête CAML.

Pour cela nous allons procéder en plusieurs étapes.

1. Les variables d'environnement

 
Sélectionnez
private int ExecuteQuery()
{
    int nbRow = 0;
    SPWeb rootWeb = SPContext.Current.Web;
    SPList spList = rootWeb.Lists["CamlSearch"];
    SPQuery spQuery = new SPQuery();

Nous allons décrire l'utilité de ces variables :

rootWeb : Il s'agit de sélectionner le site web courant.

spList : Sélection de la liste que nous avons créée précédement. Pour cela nous utilisons la variable rootWeb, car la liste que nous requêtons est dans le même site que la WebPart. (Nous verrons plus loin dans cet article comment faire pour aller chercher une liste sur un site distant)

spQuery : Il s'agit de la variable qui va contenir notre requête.

nbRow : Il s'agit d'un entier qui nous utiliserons comme compteur.

2. Le CAML

Maintenant il faut que l'on construise la requête CAML. Voici donc un exemple de ce que vous pouvez faire :

Dans cette requête nous allons chercher toutes les enregistrements où :

Le "Nom" : <FieldRef Name='Nom'/>

Est égal : <Eq>

Au "Text" "Toto" : <Value Type='Text'>Toto</Value>

De manière générale, on peut traduire cette requête par : if(Nom == "Toto")

Vous l'aurez donc certainement deviné, c'est dans la balise "<Value Type>" que nous pourrons spécifier si l'on cherche à comparer du texte, une date, un entier...

Maintenant il faut traduire cette requête en c#, et pour cela rien de plus facile, nous allons utiliser la propriété "query" de notre variable spQuery.

 
Sélectionnez
spQuery.Query = "<Where><Eq><FieldRef Name='Nom'/><Value Type='Text'>Toto</Value></Eq></Where>";

Voila, je vous l'avais dit, cette étape est simple pour peut que l'on sache ce que l'on cherche...

3. Exploitation de la requête

Bon ce n'est pas le tout maintenant, mais il faut exploiter cette requête, pour cela nous allons utiliser un "SPListItemCollection", cela va nous permettre de récupérer un collection d'items, qui va correspondre au résultat de notre requête. Il y a des centaines de raisons à vouloir récupérer ces données, pour nous le but sera d'incrémenter un simple compteur qui va nous permettre de savoir combien d'enregistrement dans ma liste correspond à ma recherche. Pour cela nous allons donc utiliser un "foreach".

 
Sélectionnez
SPListItemCollection collectionListItems = spList.GetItems(spQuery);
foreach (SPListItem oListItem in collectionListItems)
     nbRow++;

Nous retrouvons ici la variable "nbRow", qui est incrémentée chaque fois qu'un enregistrement correspond à notre recherche.

Toute personne qui à déjà créé une WebPart c'est déjà confronté à une page d'erreur de l'asp.net, et cela est très contraignant, car la page dans laquelle est placé la WebPart est inutilisable, ont est obligé d'aller dans les propriétés et de supprimer la WebPart... Une manipulation pas très agréable et assez énervante quand cela est due à une erreur de code toute bête. Je vais donc vous donner une petite astuce pour éviter cela, il faut placer notre requête dans un bloque "try catch". Comme cela nous allons pouvoir récupérer le message d'erreur et l'afficher directement dans notre WebPart et cela sans que la page soit cassée.

Pour ce faire, Visual Studio nous offre une solution très sympathique, il vous suffit de sélectionner le code que vous souhaitez placer dans votre block, ensuite fait un click droit dessus, puis sélectionner "Surround With" puis sélectionnez "try". Magique il à placer le block pour vous et il à même indenté le texte.

Bien maintenant il ne nous reste plus qu'à récupérer le message d'erreur et à afficher le résultat de notre requête.

Voici donc le code que je vous propose pour la totalité de la fonction "ExecuteQuery" :

 
Sélectionnez
private int ExecuteQuery()
{
   int nbRow = 0;
   try
   {
       SPWeb rootWeb = SPContext.Current.Web;
       SPList spList = rootWeb.Lists["CamlSearch"];
       SPQuery spQuery = new SPQuery();
       spQuery.Query = "<Where><Eq><FieldRef Name='Nom'/><Value Type='Text'>Toto</Value></Eq></Where>";
    
       SPListItemCollection collectionListItems = spList.GetItems(spQuery);
       foreach (SPListItem oListItem in collectionListItems)
           nbRow++;
   }
   catch (Exception ex)
   {
       lbl_Result = new Label();
       lbl_Result.Text = ex.Message;
   }
   return nbRow;
}

IV-B. Création de l'interface utilisateur :

L'interface utilisateur se gère dans la méthode "CreateChildControls", pour nous il s'agit ici d'afficher notre label créé précédement, le code se résume donc à cela :

 
Sélectionnez
protected override void CreateChildControls()
{
    base.CreateChildControls();
    lbl_Result = new Label();
    lbl_Result.Text = ExecuteQuery().ToString();
    this.Controls.Add(lbl_Result);
}

Ici nous n'avons rien de particulier, on instancie le label, ensuite on lui attribue le résultat de notre méthode "ExecuteQuery", sans oublier la méthode "ToString" car le label contient uniquement du texte, hors notre méthode retourne un entier. Ensuite il reste à ajouter le label à la WebPart grâce à la méthode "Controls.add".

Parfait, nous pouvons maintenant compiler notre projet à l'aide de WSPBuilder. Pour cela, suivez ces étapes :

  • Placez-vous dans la fenêtre "Solution Explorer"
  • Sélectionnez votre projet, puis click droit
  • Sélectionnez "WSPBuilder"
  • Sélectionnez "Build WSP"
Image non disponible

Maintenant il ne nous reste qu'à déployer notre WebPart, pour cela il existe trois méthodes :

  • WSPBuilder : Pour cette méthode, c'est l'outil WSPBuilder qui va travailler pour nous. Il nous suffit dans Visual Studio de sélectionner "Deploy" après avoir fait les mêmes manipulations que ci-dessus. Il va s'en dire que c'est la méthode la plus simple surtout lors de la phase de tests.
    Image non disponible
  • SharePoint Solution Installer : Cet outil est très pratique, il permet de déployer votre WebPart n'importe où. Il vous suffit de placer votre fichier WSP dans le dossier SharePoint Solution Installer, puis de modifier le fichier "Setup.exe.config" directement dans Visual Studio. Pour plus d'information je vous invite à vous rendre à cette adresse : http://SharePointinstaller.codeplex.com
  • Stsadm : Il s'agit de l'outil de base proposé avec Visual Studio, celui-ci s'utilise directement dans l'invite de commande de Visual Studio. Le descriptif de cet outil est disponible à cette adresse : http://technet.microsoft.com(Pour information, les autres outils font également appel à celui-ci, mais cela reste invisible pour l'utilisateur)

IV-C. Activation de la feature

Nous allons maintenant pouvoir aller visualiser le résultat dans SharePoint. Pour cela nous devons accéder à la liste des feature de notre site, dans le menu "Site Actions" de SharePoint et sélectionner "Site Settings".

Image non disponible

Ensuite dans le menu "Site Collection Administration" vous devez sélectionnez "Site collection features"

Image non disponible

Nous pouvons visualiser notre feature dans la liste :

Image non disponible

Il faut maintenant activer la feature, si l'opération se déroule correctement, vous devez voir apparaitre un rectangle bleu dans sur la droite de la feature, comme ceci :

Image non disponible

Parfait, nous pouvons maintenant aller ajouter notre WebPart à une page de composants WebPart. Pour créer cette page, il suffit de se rendre dans le menu "Site Actions" et de sélectionner "Create". Ensuite dans la section "Web Pages", sélectionnez "Web Part Page".

Image non disponible

Nous nommerons notre page, "TestWebPart".

Image non disponible

Maintenant il nous suffit d'ajouter notre WebPart dans la page, pour cela cliquer sur "Add a Web Part", puis sélectionner votre WebPart.

Image non disponible

Si vous avez laissé les valeurs par défaut, vous devriez trouver votre WebPart dans la section du bas nommée "MyGroup". Cochez la case correspondante puis cliquez "Add" en bas de page.

Image non disponible

Nous pouvons tout de suite visualiser le résultat de notre requête, ici "1". Félicitation! Vous venez de créer votre première WebPart contenant une requête CAML.

Image non disponible

V. CAML Avancé

Vous savez maintenant créer une WebPart qui permet de récupérer des données qui correspondent à une requête CAML. Le problème c'est que notre requête est figée dans notre code. Il est généralement plus intéressant de créer une WebPart qui permet de à son utilisateur de rechercher les données qu'il souhaite, sans avoir à demander que l'on change le code de la WebPart, cela semble impensable. Il est donc utile de savoir comment faire pour créer une WebPart qui contienne une requête paramétrée. Il existe plusieurs solutions qui dépendent des besoins en production. En voici deux qui me semblent être les plus courants:

  • L'utilisation de champs texte dans la WebPart, afin de permettre à l'utilisateur de définir des critères de recherche.
  • L'utilisation d'un éditeur personnalisé, afin que seul la personne ayant des droits suffisants puisse modifier les critères de recherche.

Il vous est maintenant aisé de créer une WebPart intégrant du CAML.


Mais il est bien souvent intéressant de pouvoir créer des requêtes un peut plus complexes, avec d'avantages de paramètres, afin de satisfaire une recherche bien spécifique.

Nous allons donc commencer par voir quels sont les éléments CAML à connaitre pour pouvoir prétendre faire une requête plus importante, et je vous donnerais ensuite des petits bout de code afin que vous puissiez les intégrer rapidement.

En premier lieu, comment utiliser plusieurs critères.

Voici la construction d'une requête CAML avec deux critères :

 
Sélectionnez
<Where>
  <And>
     <Eq>
        <FieldRef Name='Nom'/>
        <Value Type='Text'>Toto</Value>
     </Eq>
     <Eq>
        <FieldRef Name='Date'/>
        <Value Type='DateTime'>5/17/2010</Value>
     </Eq>
  </And>
</Where>
	


Descriptif de la requête :

Le champ "Nom" = Toto (champs de type Text)

Et

Le champ "Prénom" = toto (champs de type Text)


Voici un autre exemple, toujours avec deux critères :

 
Sélectionnez
<Where>
  <Or>
     <Eq>
        <FieldRef Name='Nom'/>
        <Value Type='Text'>Toto</Value>
     </Eq>
     <Eq>
        <FieldRef Name='Date'/>
        <Value Type='DateTime'>5/17/2010</Value>
     </Eq>
  </Or>
</Where>

Descriptif de la requête :

Le champ "Nom" = Toto (champs de type Text)

OU

Le champ "Date" = 5/17/2010 (champs de type date)


Comme nous pouvons le constater à l'aide de ces deux exemples, il existe de nombreuses possibilités. Ces exemples sont simples afin de bien comprendre la structure. Nous allons donc maintenant passer à des exemples plus complexes, mais toujours avec des éléments simples.

 
Sélectionnez
<Where>
  <Or>
     <And>
        <Eq>
           <FieldRef Name='Nom'/>
           <Value Type='Text'>Toto</Value>
        </Eq>
        <Eq>
           <FieldRef Name='Prénom'/>
           <Value Type='Text'>toto</Value>
        </Eq>
     </And>
     <Contains>
        <FieldRef Name='Nom'/>
        <Value Type='Text'>Ti</Value>
     </Contains>
  </Or>
</Where>

Descriptif de la requête :

le champs "Nom" = Toto (champs de type Text)

et

le champs "Prénom" = toto (champs de type Text)

OU

le champs "Nom" <> Ti (champs de type Text)


Comme nous pouvons le distinguer, une fois que l'on met en place la structure, la requête est simple, mais cela prend du temps et est assez rébarbatif. Heureusement pour nous, il existe un logiciel, très léger et très pratique, qui propose de créer les requêtes pour nous. Il s'agit de CAML Query Builder. Vous le trouverez en libre téléchargement ici.

VI. Trucs & astuces

VI-A. Requête paramétrée rapide

Maintenant, comme je vous l'ai promis, je vais vous donner quelques petits morceaux de code, afin de vous simplifier la création de requêtes CAML dans vos WebPart. Comme nous avons pu le voir, il existe quatre points indispensables dans une requête CAML :

  • La liaison
    • And
    • Or
  • Le type de comparaison
    CAMLDéfinitionTraduction
    <Eq>EqualEgal
    <Neq>Not EqualDifférent
    <Gt>Greater ThanSupérieur
    <Geq>Greater than or EqualSupérieur ou égal
    <Lt>Lower ThanPlus petit
    <Leq>Lower than or EqualPlus petit ou égal
    <IsNull>Is NullEst nul
    <Contains>ContainsContient
    <Begins With>Begins WithCommence par
  • Les champs où porte la recherche
  • Le type de la recherche
    • Text
    • Number
    • DateTime


Ces différents éléments sont assez longs à mettre en place dans le code, c'est pourquoi je vous propose ces différents codes que vous pourrez aisément glisser dans votre WebPart, afin de permettre à l'utilisateur de choisir les différents éléments de sa recherche. Il s'agit de "switch case" pour l'implémentation d'une DropDownList pour l'exemple (Le code se divise en deux parties, la première contient le code pour alimenter la "DDL" dans l'éditeur personnalisé, la seconde contient un "switch case" à placer dans le code de la WebPart). Je pense que le nom des différentes variables est assez explicite pour ne pas avoir besoin de détailler le code.

  • La Liaison :
  • Le Type de comparaison :
  • Le Type de la recherche :


C'est bien beau tout ce code, mais par forcément parlant, voici donc un exemple de sont utilisation :

 
Sélectionnez
SPQuery.Query = "<Where>"
                   + linkOperator
                       + camlOperator +
                           "<FieldRef Name='"
                           + column1 
                           + "'/><Value Type='"
                           + camlValueType + "'>"
                           + filter +
                           "</Value>"
                       + camlOperator_close
                       + camlOperator2 +
                           "<FieldRef Name='"
                           + column2 
                           + "'/><Value Type='"
                           + camlValueType2 + "'>"
                           + filter2 +
                           "</Value>"
                       + camlOperator2_close
                   + linkOperator_close +
                "</Where>";

Dans ce code, toutes les valeurs remplaçables par des variables, le sont, cela nous permet d'obtenir une requête qui peut être entièrement paramétrée par l'utilisateur.

VI-B. CAML

Voici quelques astuces afin de répondre à quelques besoins récurents :

  • Operation sur un champ de type Lookup
     
    Sélectionnez
    <Where>
    	<Eq>
    		<FieldRef Name="RefCountry" LookupId="TRUE" />
    		<Value Type="Lookup">10</Value>
    	</Eq>
    </Where>
    
  • Operation sur un champ de type User
     
    Sélectionnez
    <Where>
    	<Eq>
    		<FieldRef Name="AssignedTo" LookupId="TRUE"/>
      		<Value Type="Integer">
        		<UserID/>
      		</Value>
    	</Eq>
    </Where>
    
  • Operation sur un champ de type DateTime
     
    Sélectionnez
    <Where>
    	<Geq>
      		<FieldRef Name="MyDateColumn" />
      		<Value Type="DateTime">
        		<Today OffsetDays="-5" />
      		</Value>
    	</Geq>
    </Where>
    
  • Operation sur un champ de type DateTime avec récurrence
     
    Sélectionnez
    <Where>
    	<DateRangesOverlap>
      		<FieldRef Name="EventDate" />;
      		<FieldRef Name="EndDate" />
      		<FieldRef Name="RecurrenceID" />
      		<Value Type="DateTime">
        		<Week />
      		</Value>
    	</DateRangesOverlap>
    </Where>
    

VI-C. Bibliothèques de formulaires

Dans l'utilisation des bibliothèques de formulaires avec InfoPath, il existe une subtilité qui peux rapidement vous faire tourner en rond et perdre beaucoup de temps. En effet dans un formulaire InfoPath, il est arrive très souvent, pour ne pas dire chaque fois, que certain champs comportent un underscore, hors dans la bibliothèque de formulaire associé dans SharePoint, les colonnes correspondantes ont des espaces à la place. Voici un exemple concret :

  • Dans InfoPath : Request_Date (vue source de données)
  • Dans SharePoint : Request Date (en-tête de colonne)

Le problème est donc que dans votre WebPart vous n'aurez donc pas le bon nom. SharePoint n'a pas supprimer le underscore, mais il l'a remplacé par le code :"_x0020_".

Il existe donc une solution, utiliser la méthode "Replace" de la variable de type string. Pour reprendre l'exemple précédent, il suffit de modifier deux lignes :

column1 -> column1.Replace("_","_x0020_");

column2 -> column2.Replace("_","_x0020_");

Voilà, vous savez maintenant tout ce qu'il vous faut pour commencer à utiliser le CAML avec SharePoint. Bon courage a tous et bon code.

Un grand merci à blade159 pour la relecture de cet article ainsi qu'à nonoxpProfil de nonoxp pour sa contribution