I. Introduction▲
Les features ou fonctionnalités, comme leur nom l'indique, sont les fonctionnalités qui viennent enrichir les portails et applications SharePoint. Sous wss 3.0/moss 2007, quasiment tout est une fonctionnalité. Vous ne me croyez pas ? Eh bien regardez dans le dossier 12\TEMPLATE\FEATURES. Tous les dossiers que vous voyez apparaitre sont des fonctionnalités ! Et il y'en a plus de 200. La document Library, les basic webparts, tous sont des fonctionnalités que vous pouvez aisément installer/désinstaller, activer/désactiver. De même, vous pouvez créer et rajouter des fonctionnalités additionnelles en rajoutant un dossier. Dans la suite de cet article, après avoir défini les fonctionnalités, nous allons en créer 2 ; l'une qui va déployer de nouvelles pages maitre au sein de notre collection de site, et l'autre qui va appliquer la modification de la nouvelle master page au sein d'un site défini.
II. Tour d'horizon des features▲
Les fonctionnalités peuvent être déployées à plusieurs niveaux, au sein de notre ferme SharePoint. On va par exemple avoir des fonctionnalités qui sont déployables au niveau de la ferme toute entière, mais également au niveau d'une application web, d'une collection de site ou même d'un simple site web. A partir de l'administration centrale, dans la page des « Opérations », on va pouvoir gérer les fonctionnalités au niveau de la ferme ;
Toujours dans l'administration centrale, à partir de la page « Gestion des Applications », on va pouvoir gérer les fonctionnalités au niveau de nos applications web
Ensuite, au niveau de chacun des sites de plus haut niveau de chacune des nos collections de sites, nous allons pouvoir gérer les fonctionnalités de tous les sites de la collection.
Et enfin, au niveau de chacun des sites, nous allons pouvoir gérer les fonctionnalités de ce site. Le site de plus haut niveau de notre collection de site étant également un site en particulier, on va pouvoir, depuis la même page d'administration, gérer également les fonctionnalités de ce site.
Maintenant que nous avons vu où étaient localisées visuellement nos fonctionnalités au niveau de l'interface web, retournons dans le dossier des features. Si vous regardez à l'intérieur de chacun des dossiers représentant les fonctionnalités, vous verrez qu'il y'a toujours un fichier « Feature.xml » et d'autres fichiers/dossiers.
Ce fichier, « Feature.xml » est en fait le seul obligatoire, et c'est lui qui décrit ce qu'est la fonctionnalité. Les autres éléments sont des éléments qui seront des parties de la fonctionnalité, par exemple des webparts dans le cas ou notre fonctionnalité déploierait de nouvelles webparts, mais ces éléments ne font pas partie des éléments obligatoires pour créer une fonctionnalité. Si vous le souhaitez, vous pouvez par exemple définir une fonctionnalité qui ne contient que le fichier « Feature.xml » ; nous verrons d'ailleurs plus loin ce genre de fonctionnalités. Avec les fonctionnalités, on va pouvoir tout déployer, au sein de notre portail web ; vous trouverez une liste exhaustive de ce qu'on va pouvoir déployer ici. Lorsque vous définissez une fonctionnalité, vous lui attribuez une portée. C'est cette portée qui permet de définir le champ de visibilité de votre fonctionnalité.
Vous avez le choix entre 4 valeurs :
- Farm, pour rendre votre fonctionnalite disponible dans toute la ferme SharePoint
- WebApplication, pour rendre disponible votre fonctionnalite pour tous les sites de toutes les collections de site d'une application web
- Site, pour rendre disponible une fonctionnalite au sein d'une collection de site
- Web, pour rendre disponible une fonctionnalite au sein d'un site web unique.
Pour définir la portée de votre fonctionnalité, un bon point de départ consiste à vous interroger sur son utilité ; par exemple, si vous décidez de déployer des webparts, vous allez les héberger au sein de la webpart galerie ; cette dernière est unique au sein d'une collection de site et rend les webparts disponible pour toute la collection du site. Vous pouvez également utiliser ce lien, qui vous aide dans l'identification de la portée de votre fonctionnalité.
III. Création de nos deux features▲
Nous allons donc nous lancer dès maintenant dans la création de nos features. Comme nous l'avons déjà précisé, il nous faudra créer un fichier nommé Feaure.xml et un dossier, qui en général, porte le nom de la fonctionnalité. Toutes ces taches sont réalisables par le biais d'un fichier texte, mais nous allons tout de même faire les choses proprement et avec Visual Studio. L'objectif de cet article étant de voir le fonctionnement des features, nous ne passerons pas par les VSeWSS pour réaliser toutes nos taches.
III-A. Mise en oeuvre de notre environnement▲
Nous allons donc créer 1 nouveau projet Visual studio de type Class Library, et, pour l'instant, nous allons y créer un dossier Template, comme ci-dessous encadré en rouge (le reste sera créé au fur et à mesure).
Nous allons donc créer dans notre dossier Template 2 Features, l'une, Coforcert_MasterPages, qui sera déployée au niveau collection de site (scope = Site), va nous permettre d'uploader sur notre collection de sites de nouvelles master pages lors de l'activation de la fonctionnalité, et enfin l'autre, Coforcert_ApplyInternetMP, qui sera déployée au niveau site (scope=Web), qui va nous permettre d'appliquer la page maitre CoforcertInternet.master sur notre site. Les features que nous allons développer, dans un souci de portabilité sur des sites multilingues, ne comporteront directement aucun texte, mais utiliserons un fichier ressource. Pour ce faire, nous allons également créer un dossier « Ressources » et y stocker nos fichiers ressources ; Créez donc également ce dossier « Ressources », et ses fichiers, comme ci-dessus
III-B. Création de notre feature au niveau de la collection de site▲
Nous allons donc à présent créer notre 1ère feature, à savoir Coforcert_MasterPages, et donc créer le fichier « Feature.xml » lui correspondant. Dans cette partie, nous allons uniquement travailler dans le dossier « Coforcert_MasterPages ». Avant de se lancer dans l'édition de ce fichier, il est bon d'avoir un squelette entier de ce que peut contenir une feature. Voici ci-dessous le squelette d'un fichier Feature.xml
<?xml version="1.0" encoding="utf-8"?>
<Feature
xmlns
=
"http://schemas.microsoft.com/sharepoint/"
>
<ActivationDependencies>
<ActivationDependency/>
</ActivationDependencies>
<ElementManifests>
<ElementManifest/>
<ElementFile/>
</ElementManifests>
<Properties>
<Property/>
</Properties>
</Feature>
Cependant, avant de commencer à rédiger ces fichiers, nous allons importer un certain nombre de schémas xsd, afin de pouvoir bénéficier de la fonctionnalité d'IntelliSense avec Visual Studio. Pour cela, rendez vous dans le dossier 12\Template\XML, et copiez tous les fichiers portant l'extension « xsd ». Ce sont les fichiers définissant tous les schémas utilisés par SharePoint.
Nous allons copier tous ces fichiers dans le dossier « C:\Program Files\Microsoft Visual Studio 9.0\Xml\Schémas », dossier correspondant à tous les schémas de Visual studio 2008. Ceci étant fait, maintenant, lorsque nous créerons de nouveaux fichiers respectant les schémas pour SharePoint avec Visual Studio, nous bénéficierons automatiquement de l'auto complétion ; pour cela, lorsque l'on créera un nouveau fichier XML correspondant à un schéma SharePoint, il nous suffira d'importer le schéma. Dans cet article, l'unique schéma dont nous aurons besoin est le « wss.xsd ». Lors de la création donc d'un fichier XML, il suffit d'afficher la fenêtre des propriétés, et d'importer le schéma.
Pour en revenir à notre feature, nous allons uniquement référencer un nouveau fichier xml, qui nous servira à décrire les fichiers que nous allons importer grâce à notre feature. Pour cela, nous allons créer, à l'intérieur du dossier « Coforcert_MasterPages » un nouveau fichier que nous allons appeler, par convention, elements.xml. Nous allons ensuite référencer ce fichier au niveau de notre feature grâce à l'élément « ElementManifest » Ceci étant fait, éditons à présent notre fichier Feature.xml. Ci-dessous le code complet de notre fichier.
<?xml version="1.0" encoding="utf-8"?>
<Feature
Id
=
"1AC630A7-5A31-4e7c-8A44-74B7EAFD9773"
Description
=
"$Resources:Coforcert_MasterPages,Description;"
ImageUrl
=
"/_layouts/IMAGES/RootPagesLib.gif"
Scope
=
"Site"
Title
=
"$Resources:Coforcert_MasterPages,Title;"
Version
=
"1.0.0.0"
xmlns
=
"http://schemas.microsoft.com/sharepoint/"
>
<ElementManifests>
<ElementManifest
Location
=
"elements.xml"
/>
</ElementManifests>
</Feature>
Comme vous pouvez le remarquer dans les attributs Description et Title, nous précisons que nous utilisons un fichier de ressources ($Resources), que ce fichier de ressources se nomme Coforcert_MasterPages, et que nous allons récupérer de ce fichier la valeur Description, dans le 1er cas, et Title, dans le 2ème cas. Nous devons ensuite éditer nos fichiers, afin de fournir ces valeurs. Ci-dessous, le fichier Coforcert_MasterPages.fr-fr.resx
Et ci-dessous, le 2ème fichier de ressources, lui aussi en version française.
Nous aurions également pu créer des fichiers pour des langues supplémentaires. Visuellement, voici le résultat obtenu, une fois nos features déployées.
A cette étape, nous avons donc créé notre fichier Feature.xml dans notre dossier « Coforcert_MasterPage », et édité nos 2 fichiers de ressources, dans notre dossier « Resources ». Pour terminer notre feature, il ne nous reste plus qu'à éditer notre fichier « elements.xml ».
C'est dans ce fichier, elements.xml, que nous allons spécifier que nous allons déployer nos mater pages. Pour ce faire, nous allons importer des fichiers dans notre bibliothèque de pages maitre au niveau de notre collection de site. Sous SharePoint, à chaque fois que nous allons déployer des fichiers, nous déploierons en fait des modules contenant ces fichiers. Ci-dessous le code nous permettant de déployer 4 master pages, coforcert.master, coforcertintra.master, coforcertextra.master et coforcertinter.master
<?xml version="1.0" encoding="utf-8" ?>
<Elements
Id
=
"A08AFBFF-373C-422b-8C48-4F4D67FCA016"
xmlns
=
"http://schemas.microsoft.com/sharepoint/"
>
<Module
List
=
"116"
Url
=
"_catalogs/masterpage"
Name
=
"Coforcert MasterPages"
Path
=
"masterpages"
RootWebOnly
=
"True"
>
<File
Url
=
"coforcert.master"
Type
=
"GhostableInLibrary"
/>
<File
Url
=
"coforcertintra.master"
Type
=
"GhostableInLibrary"
/>
<File
Url
=
"coforcertextra.master"
Type
=
"GhostableInLibrary"
/>
<File
Url
=
"coforcertinter.master"
Type
=
"GhostableInLibrary"
/>
</Module>
</Elements>
L'attribut List, permet de spécifier dans quelle type de liste les fichiers vont être déployés ; 116 correspond à la catalog masterpage ; l'attribut Url permet de spécifier l'url de ladite liste, l'attribut Path permet de définir où se trouvent les fichiers à importer ; dans notre cas, ils sont dans notre dossier masterpages dans Visual studio, et enfin l'attribut GhostableInLibrary permet de spécifier que nos fichiers seront mis en cache dans notre bibliothèque.
Voila c'en est terminé pour notre Feature au niveau Collection de Site ; finalement, ce n'était pas sorcier ! Nous allons maintenant réaliser notre 2ème feature, celle qui sera déployée au niveau site.
III-C. Création de notre feature au niveau site▲
Cette fonctionnalité, « Coforcert_ApplyInternetMP », une fois les master pages déployées, va nous permettre d'installer, lors de son activation, la master page nommée « coforcertinter.master ». En plus de cela, pour compliquer un peu la tache, elle va nous créer une liste annonce et rajouter une annonce à chaque activation/désactivation de la feature, et pour terminer, va nous rajouter un lien « Gestion Des Fonctionnalités », dans le menu « Actions du Site ».
Procédons par étapes. Nous allons commencer par installer, lors de l'activation de la feature au niveau collection de site, notre feature au niveau site. Ici, nous allons gérer les dépendances au niveau des features.
<ActivationDependencies>
<ActivationDependency
FeatureId
=
"1AC630A7-5A31-4e7c-8A44-74B7EAFD9773"
/>
</ActivationDependencies>
Le « FeatureId » correspond à l'id de la feature précédemment développée et qui sera déployée au niveau de la collection. De même, il va nous falloir déclencher quelque part une action lors de l'interception de l'activation de la Feature ; nous allons en fait, écrire un « Feature Receiver»
<Feature
Id
=
"277E2BFB-C895-464a-AA3C-23D3DCB22137"
Description
=
"$Resources:Coforcert_ApplyInternetMP,Description;"
ImageUrl
=
"/_layouts/IMAGES/Posts.png"
Scope
=
"Web"
Title
=
"$Resources:Coforcert_ApplyInternetMP,Title"
Version
=
"1.0.0.0"
ReceiverAssembly
=
"Project, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=04dd87c088df5ca8"
ReceiverClass
=
"Coforcert.Assemblies.ReceiverAssembly"
xmlns
=
"http://schemas.microsoft.com/sharepoint/"
>
On aurait pu s'arrêter ici, mais on va également rajouter une action dans le menu « Action du Site », et pour cela, on va à nouveau spécifier un fichier xml complémentaire, que nous allons appeler « ManageFeature.xml ». Voici le code complet du fichier « Feature.xml »
<?xml version="1.0" encoding="utf-8"?>
<Feature
Id
=
"277E2BFB-C895-464a-AA3C-23D3DCB22137"
Description
=
"$Resources:Coforcert_ApplyInternetMP,Description;"
ImageUrl
=
"/_layouts/IMAGES/Posts.png"
Scope
=
"Web"
Title
=
"$Resources:Coforcert_ApplyInternetMP,Title"
Version
=
"1.0.0.0"
ReceiverAssembly
=
"Project, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=04dd87c088df5ca8"
ReceiverClass
=
"Coforcert.Assemblies.ReceiverAssembly"
xmlns
=
"http://schemas.microsoft.com/sharepoint/"
>
<ActivationDependencies>
<ActivationDependency
FeatureId
=
"1AC630A7-5A31-4e7c-8A44-74B7EAFD9773"
/>
</ActivationDependencies>
<ElementManifests>
<ElementManifest
Location
=
"ManageFeature.xml"
/>
</ElementManifests>
</Feature>
Et celui du fichier « ManageFeature.xml »
<?xml version="1.0" encoding="utf-8" ?>
<Elements
xmlns
=
"http://schemas.microsoft.com/sharepoint/"
>
<CustomAction
Id
=
"UserInterfaceLightUp.SiteActionsToolbar"
GroupId
=
"SiteActions"
Location
=
"Microsoft.SharePoint.StandardMenu"
Sequence
=
"1000"
Title
=
"$Resources:Coforcert_ApplyInternetMP,FeatureManagement;"
>
<UrlAction
Url
=
"/_layouts/ManageFeature.aspx"
/>
</CustomAction>
</Elements>
Maintenant, il ne nous reste plus qu'à implémenter notre classe « Feature Receiver », et le tour sera joué. Pour cela, dans le dossier « Assembly », nous allons créer une nouvelle classe et la faire dériver de SPFeatureReceiver, comme le code ci-dessous.
using
System;
using
System.
Collections.
Generic;
using
System.
Linq;
using
System.
Text;
using
Microsoft.
SharePoint;
using
System.
Globalization;
namespace
Coforcert.
Assemblies {
public
class
ReceiverAssembly :
SPFeatureReceiver {
public
SPList GetAnnouncementList
(
) {
//Crée une nouvelle liste d'annonce Feature Logs, ou la récupère si elle est déjà créée
SPWeb web =
SPContext.
Current.
Web;
string
listName =
"Feature Logs"
;
SPList list =
null
;
foreach
(
SPList currentList in
web.
Lists){
if
(
currentList.
Title.
Equals
(
listName,
StringComparison.
InvariantCultureIgnoreCase)) {
list =
currentList;
break
;
}
}
if
(
list ==
null
)
{
string
descr =
@"Liste utilisée pour logguer les évenements des features"
;
Guid listID =
web.
Lists.
Add
(
listName,
descr,
SPListTemplateType.
Announcements);
list =
web.
Lists[
listID];
list.
OnQuickLaunch =
true
;
list.
Update
(
);
}
return
list;
}
public
override
void
FeatureActivated
(
SPFeatureReceiverProperties properties) {
//Change la master page puis met à jour le site
SPWeb currentWeb =
SPContext.
Current.
Web;
string
currentWebUrl =
currentWeb.
Url;
currentWeb.
MasterUrl =
"/_catalogs/masterpage/coforcertinter.master"
;
currentWeb.
Update
(
);
//Crée un nouvel item dans la liste puis la met à jour
SPList aList =
GetAnnouncementList
(
);
SPListItem item =
aList.
Items.
Add
(
);
SPListItem item1 =
aList.
Items.
Add
(
);
SPListItem item2 =
aList.
Items.
Add
(
);
aList.
Update
(
);
//modifie le nouvel item créé puis le met à jour
item[
"Title"
]
=
"Nouvel Evenement - "
+
properties.
Definition.
DisplayName;
item[
"Body"
]
=
string
.
Format
(
"La fonctionnalité {0} a été activé le {1}"
,
properties.
Definition.
GetTitle
(
CultureInfo.
CurrentUICulture),
DateTime.
Now);
item[
"Expires"
]
=
DateTime.
Now.
AddDays
(
1
);
item.
Update
(
);
}
public
override
void
FeatureDeactivating
(
SPFeatureReceiverProperties properties) {
SPWeb currentWeb =
SPContext.
Current.
Web;
string
currentWebUrl =
currentWeb.
Url;
currentWeb.
MasterUrl =
"/_catalogs/masterpage/default.master"
;
currentWeb.
Update
(
);
SPList aList =
GetAnnouncementList
(
);
SPListItem item =
aList.
Items.
Add
(
);
item[
"Title"
]
=
"Nouvel Evenement - "
+
properties.
Definition.
DisplayName;
item[
"Body"
]
=
string
.
Format
(
"La fonctionnalité {0} a été désactivé le {1}"
,
properties.
Definition.
GetTitle
(
CultureInfo.
CurrentUICulture),
DateTime.
Now);
item.
Update
(
);
aList.
Update
(
);
}
public
override
void
FeatureInstalled
(
SPFeatureReceiverProperties properties){}
public
override
void
FeatureUninstalling
(
SPFeatureReceiverProperties properties){}
}
}
Les méthodes se terminant en ing (FeatureUninstalling, FeatureDeactivating), sont des méthodes qui s'exécutent avant l'action ; ici ce sera avant la désinstallation ou avant la désactivation. Les autres se terminant en ed, s'exécutent après. Une fois ceci terminé, il ne reste plus qu'à traiter le déploiement et notre projet sera terminé.
III-D. Déploiement de nos features▲
Une fois nos features implémentées, il va falloir les déployer. Pour cela, rien ne vaut une bonne veille méthode « manuelle ». Pour déployer nos features, il va falloir les copier dans leur répertoire, à savoir le 12/Template/Features. De même, notre Assembly, il va falloir la déployer, soit dans le GAC, soit dans le bin de notre application web, et enfin copier également nos fichiers de ressources dans le répertoire 12/Resources.
Pour effectuer toutes ces taches, et être sur de n'en oublier aucune, rien ne vaut un bon script. Créez au sein de votre projet, un fichier « install.bat », et ajoutez-y ces quelques commandes :
@
SET
GACUTIL=
"C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin\gacutil.exe" %GACUTIL%
-i bin\debug
\Projet.dll
@
SET
TEMPLATEDIR=
"c:\program files\fichiers communs\microsoft shared\web server extensions\12\Template"
xcopy
/e /y TEMPLATE\*
%TEMPLATEDIR%
@
SET
RESOURCESDIR=
"c:\program files\fichiers communs\microsoft shared\web server extensions\12\Resources"
xcopy
/e /y Resources\*
%RESOURCESDIR%
@
SET
STSADM=
"c:\program files\fichiers communs\microsoft shared\web server extensions\12\bin\stsadm"
%STSADM%
-o installfeature -filename Coforcert_MasterPages\feature.xml -force
%STSADM%
-o installfeature -filename Coforcert_ApplyInternetMP\feature.xml -force
%STSADM%
-o activatefeature -filename Coforcert_MasterPages\feature.xml -force -url http://wss3/sites/dev
cscript
c:\windows\system32\iisapp.vbs /a "SharePoint - 80" /r
A la place de SharePoint - 80, renseignez le nom du pool d'application que vous utilisez, ou remplacez carrément toute la ligne par « IISRESET ». Néanmoins, l'utilisation de cette ligne par rapport à IISReset est un gain de temps considérable. Testez par vous-même ! Ensuite, étant donné que nous déployons notre Assembly dans le GAC, nous allons devoir la signer. Pour cela, dans l'explorateur de solutions, cliquez droit sur le nom projet et choisissez d'afficher ses propriétés.
Dans l'onglet « Signing », choisissez de signer l'Assembly
Ensuite, toujours dans les propriétés du projet, allez sur l'onglet « Build Events » et remplissez comme ci-dessous.
Vous spécifiez tout simplement à Visual Studio qu'à chaque fois qu'il réussit à compiler le code, il doit se positionner dans le répertoire du projet et exécuter le fichier install.bat A ce niveau, le déploiement des fichiers au bon endroit sera correctement effectué, d'ailleurs je vous conseille de le vérifier. Il vous faudra par la suite installer et activer les fonctionnalités. En fait l'installation des fonctionnalités a déjà été réalisée, ainsi que l'activation de la fonctionnalité niveau collection de site, grâce aux commandes suivantes exécutées dans le fichier bat.
%STSADM%
-o installfeature -filename Coforcert_MasterPages\feature.xml -force
%STSADM%
-o installfeature -filename Coforcert_ApplyInternetMP\feature.xml -force
%STSADM%
-o activatefeature -filename Coforcert_MasterPages\feature.xml -force -url http://wss3/sites/dev
Si nous nous connectons dès maintenant à la page de gestion des features au niveau collection de site, nous obtenons le résultat ci-dessous.
La fonctionnalité a donc bien été installée ; cette fonctionnalité, rappelons-le, est censée déployer de nouvelles master pages dans la masterpage galerie ; allons le vérifier. Depuis la page de gestion du site, cliquez sur pages maitre.
Nous sommes redirigés vers la galerie des pages maitres, et cette dernière contient bien nos nouvelles pages maitres.
Si par contre nous allons sur la page de gestion des fonctionnalités du site web, cette dernière n'a pas encore été activée.
Nous pouvons activer/désactiver des fonctionnalités depuis l'interface web, mais pas les installer/désinstaller. Activons-la ! Instantanément, plusieurs choses se produisent ; d'une part, la master page change (dans mon cas j'ai fait une copie de la master page par défaut et rajouté du texte), ensuite une nouvelle liste nommée « Feature Log » fait également son apparition dans la quick lauch et de nouvelles annonces y sont publiées, et pour terminer une nouvelle action apparait dans le menu « Actions du Site ».
SI cependant, nous désactivons la fonctionnalité « Coforcert_MasterPages » et tentons d'activer la fonctionnalité « Coforcert_ApplyInternetMP », nous recevrons un message d'erreur lié aux dépendances qui existent entre les 2 fonctionnalités.
IV. Conclusion▲
Dans cet article, vous aurez appris à travailler avec les fonctionnalités de base liées aux Features.
Vous aurez notamment appris à :
- Déployer des features
- Creer des dependances de features
- Creer un event receiver pour une feature
- Utiliser les fichiers de ressources de langue avec des features
- Rajouter une action dans le menu Action du Site grace aux features
- Deployer de nouvelles master pages via des features et changer dynamiquement la master page via un evenement de feature
- Mettre une master page en Cache dans une librairie de document
- Creer une liste et ajouter des evenements, suite a l'activation d'une feature, etc...