Ted Pattison et Fritz Onion
Cet article repose sur une version préliminaire d'ASP.NET 2.0. Toutes les informations contenues dans le présent document peuvent faire l'objet de modifications.
Cet article présente les points suivants :
| • | Utilisation des composants WebPart pour créer des applications de portail Web modulaires |
| • | Fonctions de personnalisation et de customisation |
| • | Utilisation des contrôles utilisateur personnalisés en tant que composants WebPart |
| • | Création d'un fournisseur de personnalisation |
Les applications de portail sont très en vogue aujourd'hui et les meilleures présentent certains points communs. Les portails bien conçus offrent un contenu fourni au travers d'une interface utilisateur modulaire, cohérente et facile à consulter. Les portails les plus élaborés vont même plus loin en permettant aux membres du site d'ajouter du contenu, de soumettre des documents et de personnaliser les pages du portail.
Microsoft a ajouté à la plate-forme Windows Server™ 2003, avec la sortie de Windows® SharePoint® Services, une structure de portail évolutive qui fournit les éléments de base d'une structure de portail et prend en charge l'appartenance au site, la gestion du contenu et des documents, ainsi que la présentation modulaire des données grâce aux composants WebPart.
Les composants WebPart fournissent les éléments de base nécessaires à la customisation et à la personnalisation. En fonction de la configuration du site, les utilisateurs peuvent facilement personnaliser ou customiser les pages d'un site Windows SharePoint Services en ajoutant, reconfigurant ou supprimant des composants WebPart. Le développement de composants WebPart personnalisés est une solution puissante qui permet d'étendre facilement les sites utilisant Windows SharePoint Services. Créer un composant WebPart personnalisé qui prend en charge la customisation et la personnalisation consiste simplement à ajouter des propriétés à votre classe WebPart et à appliquer quelques attributs spécifiques. L'infrastructure WebPart de Windows SharePoint Services se charge du plus gros du travail : sérialisation, stockage et récupération des données associées à la customisation du site et à la personnalisation des membres.
ASP.NET 2.0 introduit un jeu de contrôles WebPart similaire à Windows SharePoint Services dans la mesure où il a été conçu pour la sérialisation, le stockage et la récupération des données de customisation et de personnalisation en arrière-plan. Il est néanmoins différent et plus flexible, n'étant pas étroitement lié à SQL Server™ ou Active Directory®. C'est une excellente nouvelle pour les entreprises qui souhaitent créer des applications de portail utilisant l'authentification basée sur les formulaires ou qui ne veulent pas être liées à une solution de base de données particulière.
Figure 1 Exemple de portail affichant une architecture WebPart modulaire
Cet article vous fait découvrir un exemple d'application de portail écrit dans ASP.NET 2.0 à partir de composants WebPart. Son objectif principal est de vous présenter les principaux problèmes de conception que pose le développement de composants WebPart pour une application de portail. Nous commencerons pas souligner les principaux concepts et types de contrôles impliqués dans l'utilisation du nouveau jeu de contrôles WebPart d'ASP.NET 2.0. Pour voir un exemple, consultez la figure 1.
Notions élémentaires sur les composants WebPart
Figure 2 Mise en page habituelle d'une page WebPartUne page conçue pour héberger des composants WebPart est appelée « page WebPart ». Une page WebPart requiert exactement une instance du contrôle WebPartManager et un ou plusieurs contrôles WebPartZone, comme illustré à la figure 2. Une page WebPart peut également inclure un contrôle EditorZone ou CatalogZone. Notez que la balise du contrôle WebPartManager doit être placée dans un fichier .aspx avant les balises des autres contrôles associés à l'infrastructure WebPart, comme WebPartZone, EditorZone ou CatalogZone. Pour mieux contrôler la mise en page et l'apparence de la page WebPart, vous pouvez aussi utiliser des tables HTML pour présenter les différentes zones dans le fichier .aspx.
Nous allons commencer par un exemple simple de page WebPart contenant des contrôles WebPartManager et WebPartZone :
‹asp:WebPartManager ID=" WebPartManager1" runat="server" /> ‹asp:WebPartZone ID="WebPartZone1" runat="server" HeaderText="Zone 1"> ‹/asp:WebPartZone>
Une fois que vous avez un contrôle WebPartZone, vous pouvez utiliser une définition WebPart pour créer une instance WebPart. Il existe deux façons de créer une définition WebPart. La première consiste à créer une classe personnalisée qui hérite de la classe WebPart. La deuxième consiste à créer un contrôle utilisateur. Nous étudierons plus en détail les avantages et inconvénients respectifs de ces deux approches plus loin dans cet article. Pour l'instant, commençons par écrire une classe simple, dérivée de WebPart (voir figure 3).
Chaque instance de composant WebPart existe sur une page spécifique d'un contrôle WebPartZone donné, sous un index qui lui est propre. Un contrôle WebPartZone peut contenir plusieurs composants WebPart. Par exemple, la figure 4 montre deux composants WebPart dans la zone appelée WebPartZone1.
Figure 4 Composants WebPart dans une zone spécifique
Vous pouvez ajouter un composant WebPart dans une zone soit par programmation soit par le biais d'une déclaration. Vous verrez aussi plus loin une technique pour ajouter des composants WebPart dans un catalogue de composants. Une fois que vous aurez créé un composant CatalogPart, vos utilisateurs pourront ajouter de nouveaux composants WebPart dans les WebPartZone à l'exécution.
Il existe différentes façons d'ajouter des composants WebPart à des contrôles WebPartZone selon le type de composants WebPart que vous utilisez. Si votre classe hérite de WebPart, vous pouvez créer par programmation une instance de la classe et appeler la méthode AddWebPart de la classe WebPartManager. Lorsque vous appelez AddWebPart, vous devez transmettre des paramètres spécifiant l'instance WebPart, la cible WebPartZone et l'index sous lequel le composant WebPart apparaîtra dans la zone cible :
// create Web Part instance from WebPart-derived class WebPart wp1 = new WingtipWebParts.HelloWorld(); WebPartManager1.AddWebPart(wp1, WebPartZone1, 0);Il s'agit là de la technique utilisant la programmation pour ajouter un composant WebPart à un contrôle WebPartZone. L'approche déclarative consiste à utiliser des balises de contrôle dans le fichier .aspx de la page WebPart. Si vous souhaitez qu'un composant WebPart apparaisse dans un contrôle WebPartZone spécifique la première fois que la page est récupérée par un utilisateur, vous pouvez ajouter un contrôle ZoneTemplate dans le contrôle WebPartZone :
‹%@ Register Assembly="WingtipWebParts" Namespace="WingtipWebParts"
TagPrefix="Wingtip" %>
‹asp:WebPartManager ID=" WebPartManager1" runat="server" />
‹asp:WebPartZone ID="WebPartZone1" runat="server" HeaderText="Zone 1">
‹Wingtip:HelloWorld runat="server" id="HelloWorld" />
‹/asp:WebPartZone>
N'oubliez pas que vous devez habiller un peu vos composants WebPart si vous voulez qu'ils attirent l'attention sur une page WebPart. L'une des fonctions couramment sollicitée dans les applications de portail est la possibilité de personnaliser l'apparence du site (« skinning »), c'est-à-dire d'en changer l'apparence en fonction des préférences des utilisateurs. Auparavant, cela supposait de créer sa propre infrastructure pour prendre en charge les changements de rendu des contrôles, ce qui impliquait une grosse somme de travail si l'on voulait que tout fonctionne bien. ASP.NET 2.0 introduit le concept des « thèmes ». Il s'agit de collections de styles et d'attributs de contrôle applicables à chaque contrôle individuellement, à une page entière, ou même à l'ensemble de l'application.
Pour que votre application de portail ait l'allure d'une application professionnelle, personnalisez l'apparence de tous les contrôles WebPartZone, EditorZone et CatalogZone. C'est un exercice qui peut sembler fastidieux la première fois car il suppose de personnaliser l'apparence graphique (« skinning ») et l'image de marque (« branding ») du corps, des barres de titre et des menus dynamiques des composants WebPart, EditorPart et CatalogPart. Heureusement, grâce aux thèmes, nouvelle fonctionnalité d'ASP.NET 2.0, il est possible d'effectuer tout ce travail visuel en dehors des fichiers .aspx, dans des fichiers .skin et .css réutilisables. L'exemple d'application de portail présenté dans cet article personnalise l'apparence des composants WebPart en utilisant les skins et les thèmes. Il est disponible sur le site Web MSDN® Magazine.
Modes d'affichage et portée de page
Sur chaque page WebPart, une seule instance du contrôle WebPartManager s'exécute et prend en charge la gestion des instances WebPart et de leurs relations avec les contrôles WebPartZone. Le contrôle WebPartManager fournit également une interface de programmation qui permet de basculer entre les différents modes d'affichage de la page WebPart : navigation, création ou édition. Par exemple, pour faire basculer par programmation la page en cours en mode création, il vous suffit d'ajouter un contrôle de lien avec un gestionnaire d'événements attribuant à la propriété DisplayMode la valeur DesignDisplayMode :
WebPartManager1.DisplayMode = WebPartManager.DesignDisplayMode;
Il est important de bien distinguer les différents modes d'affichage d'une page WebPart. Par défaut, une page WebPart fonctionne en mode navigation, ce qui empêche l'utilisateur de modifier les composants WebPart. Lorsqu'une page WebPart bascule en mode création, l'utilisateur peut alors déplacer des composants WebPart au sein d'un même contrôle WebPartZone ou d'une zone à l'autre. La figure 5 présente les modes d'affichage disponibles.
Les contrôles WebPart ASP.NET 2.0 fournissent en arrière-plan tout le DHTML et le JavaScript nécessaires pour activer la fonction glisser-déplacer au sein du navigateur. Pour les navigateurs qui ne prennent pas en charge les fonctions DHTML et JavaScript, seule la fonction glisser-déplacer n'est pas assurée ; les autres demeurent intactes. Vous n'avez donc pas à vous inquiéter : inutile d'obliger tous vos clients à utiliser Microsoft® Internet Explorer 5.0 ou version ultérieure. Les contrôles WebPart ASP.NET 2.0 s'occupent aussi de gérer le stockage et la récupération des données de personnalisation pour rappeler où les utilisateurs ont placé les composants WebPart lors des sessions antérieures.
Non seulement le contrôle WebPartManager permet à votre code de basculer d'un mode à l'autre, mais il fournit aussi la possibilité de modifier la portée de la page WebPart qui peut être soit attribuée à l'utilisateur, soit partagée. La portée de la page indique la nature d'une modification sur un composant WebPart : customisation ou personnalisation. Rappelons que les modifications de customisation sont visibles par tous les utilisateurs alors que les modifications de personnalisation ne sont visibles que par l'utilisateur qui les a effectuées. Pour modifier une page WebPart, il faut appeler la méthode ToggleScope du contrôle WebPartManager, comme présenté ci-dessous :
WebPartManager1.Personalization.ToggleScope();
La portée par défaut est la portée utilisateur : les modifications apportées aux composants WebPart sont enregistrées en tant que personnalisations et ne sont visibles que par l'utilisateur actuel. Si l'appel de la méthode ToggleScope aboutit, la page WebPart passe en portée partagée : les modifications sont alors enregistrées en tant que customisations. L'objectif de la portée partagée est de permettre à l'administrateur ou au créateur du site d'effectuer des modifications globales de customisation sur les composants WebPart d'une page WebPart qui seront visibles par tous les utilisateurs. En cas de chevauchement, les modifications de personnalisation effectuées par les utilisateurs ont toujours priorité sur les customisations globales.
Il n'est pas toujours possible pour l'utilisateur en cours de passer en portée partagée. Par défaut, les utilisateurs n'ont pas les autorisations requises pour passer en portée partagée. L'utilisateur doit en obtenir l'autorisation dans le fichier Web.config. Voici un exemple qui montre comment autoriser tous les utilisateurs ayant un rôle d'administrateur (admin) ou de créateur de site (site_designer) à passer en portée partagée et à modifier les customisations globales :
Propriétés et personnalisation
Chaque objet WebPart est doté d'un jeu de propriétés standard qui peut être customisé ou personnalisé. Par exemple, chaque composant WebPart a une propriété Title (Titre) qui peut être customisée une fois ajoutée à un contrôle WebPartZone. Le contrôle EditorZone et divers composants EditorPart permettent aux utilisateurs de modifier les propriétés WebPart.
Lorsque l'utilisateur définit la page WebPart sur EditDisplayMode, le menu WebPart fournit une commande d'édition (Edit). L'invocation de la commande Edit sur un composant WebPart particulier appelle le contrôle EditorZone ainsi que tous les composants EditorPart placés dans la zone en question. ASP.NET 2.0 est fourni avec plusieurs composants EditorPart intégrés qui permettent de modifier l'apparence, le comportement et la présentation des composants WebPart.
Le schéma de personnalisation WebPart est facile à étendre par l'ajout de propriétés qui peuvent être personnalisées. Il vous suffit d'ajouter des propriétés à une définition de classe WebPart et de lui attribuer des attributs de type Personalizable, WebBrowsable ou WebDisplayName. Cela fait, les contrôles WebPart se chargeront de stocker et de récupérer les valeurs des propriétés customisées ou personnalisées.
Lorsque vous créez une propriété de personnalisation, il est généralement utile de définir en même temps un champ privé comme illustré ci-dessous :
private bool _HR = true;
[Personalizable(PersonalizationScope.User),
WebBrowsable, WebDisplayName("Show HR News"),
WebDescription("Use this property to show/hide HR news")]
public bool HR
{
get { return _HR; } set { _HR = value; }
}
Si vous souhaitez autoriser vos utilisateurs à personnaliser une propriété de cette façon, il vous suffit d'ajouter un contrôle PropertyGridEditorPart dans un contrôle EditorZone de la page en cours. La figure 6 montre comment cette opération se traduira pour les utilisateurs.
Figure 6 Les composants EditorPart permettent aux utilisateurs de personnaliser les composants WebPart
Si vous définissez une propriété WebPart à partir d'une chaîne ou d'un type numérique, PropertyGridEditorPart fournira une zone de texte permettant à l'utilisateur de modifier la valeur. Si vous définissez une propriété WebPart à partir d'une valeur booléenne, PropertyGridEditorPart fournira une case à cocher comme illustré à la figure 6.
La figure 7 montre une astuce de programmation judicieuse, issue du développement de composants WebPart dans Windows SharePoint Services : vous pouvez définir une propriété de personnalisation dont le type est basé sur une énumération.
Le véritable avantage de créer une propriété de personnalisation WebBrowsable à partir d'une énumération est que PropertyGridEditorPart génère une liste déroulante des paramètres de propriété disponibles pour l'utilisateur, comme illustré pour la propriété Timeframe à la figure 7. Cette solution, très pratique pour l'utilisateur, garantit en outre que la valeur de propriété sélectionnée par l'utilisateur sera valide.
Soulignons un autre point important concernant la définition de la propriété Timeframe. Elle a été définie avec un attribut Personalizable ayant la valeur PersonalizationScope.Shared. Lorsqu'une propriété est ainsi définie en tant que propriété partagée, elle peut être customisée mais pas personnalisée. Comme une propriété partagée n'est pas personnalisable, elle ne s'affiche pas dans le composant PropertyGridEditorPart lorsque la page WebPart en cours est en portée utilisateur. Elle ne s'affiche que si la page est en portée partagée.
Catalogues WebPart
Vous avez vu que les pages WebPart permettent de préremplir les contrôles WebPartZone avec des composants WebPart. Vous pouvez compléter cette technique par une autre méthode qui consiste à permettre aux utilisateurs d'ajouter de nouveaux composants WebPart à l'exécution. Pour cela, vous devez utiliser un contrôle CatalogZone et des contrôles CatalogPart comme PageCatalogPart ou DeclarativeCatalogPart (voir figure 8).
Une fois les contrôles CatalogZone et CatalogPart ajoutés, les utilisateurs pourront ajouter de façon dynamique à l'exécution des composants WebPart par l'intermédiaire d'une interface utilisateur comme celle présentée à la figure 9.
Figure 9 Les contrôles CatalogZone permettent aux utilisateurs d'ajouter des composants WebPart de façon dynamique
Vous devez avant tout comprendre à quoi sert PageCatalogPart. En mode de conception ou d'édition de l'affichage, l'utilisateur a la capacité d'invoquer la commande Close (Fermer) pour un composant WebPart. Lorsqu'un utilisateur ferme un composant WebPart, ce dernier est conservé avec tous ses paramètres de personnalisation et de customisation, ce qui permet à l'utilisateur de l'ajouter à nouveau plus tard. Par conséquent, le contrôle PageCatalogPart affiche une liste de tous les composants WebPart qui ont été fermés et peuvent être ajoutés à la page.
La commande Close (Fermer) est différente de la commande Delete (Supprimer). La commande Delete n'est disponible qu'en mode d'édition de l'affichage. Lorsqu'un utilisateur supprime un composant WebPart, toutes les informations sur l'existence de ce composant, y compris les données de personnalisation et de customisation, sont éliminées de la mémoire.
Il est possible de remplir un contrôle DeclarativeCatalogPart avec des composants WebPart au moyen d'une déclaration. Le code présenté à la figure 8 montre comment introduire dans le catalogue un composant WeatherWebPart avec un nom personnalisé. Cette approche vous permet de rendre toutes sortes de composants WebPart accessible à vos utilisateurs.
Pour compléter cet article et obtenir plus de détails pratiques sur la création de pages WebPart, nous vous recommandons de lire l'article de Stephen Walther intitulé « Introducing the ASP.NET 2.0 Web Parts Framework » (en anglais). Il fournit des informations complémentaires et des exemples fonctionnels sur la création de pages WebPart à l'aide de contrôles EditorZone et CatalogZone. Stephen aborde aussi des sujets plus pointus comme les verbes, les connexions ou l'importation et l'exportation de composants WebPart.
Développement de portails ASP.NET 2.0
Outre l'infrastructure WebPart elle-même, il existe plusieurs nouvelles fonctionnalités qui rendent le développement de sites portail Intranet séduisant dans ASP.NET 2.0. Comme nous l'avons déjà mentionné dans cet article, l'introduction de thèmes et de skins facilite grandement l'isolation des propriétés de style dans les pages de portail et permet des changements globaux de style sans qu'il soit nécessaire de modifier les pages individuelles. Autre apport plus étonnant encore : l'introduction des pages maître. Avec les pages maîtres, vous pouvez isoler tous vos contrôles WebPartZone et l'ensemble du contrôle WebPartManager dans un seul modèle de page dont les pages individuelles hériteront l'apparence et la fonctionnalité de base. Dans l'exemple de portail, nous utilisons une technique intéressante : l'ajout de contrôles ContentPlaceholder dans le composant ZoneTemplate de chaque WebPartZone de la page maître. Ainsi, les pages de contenu qui utilisent cette page maître peuvent ajouter leurs propres composants WebPart en utilisant des contrôles Content qui ont chacun un contrôle ContentPlaceHolder correspondant.
Lorsque vous créez une page maître pour un site portail, vous devez décidez entre autres comment rendre les fonctions de customisation accessibles aux utilisateurs. Comme vous l'avez vu, en fonction des types de zones ajoutés à la page, l'utilisateur a le choix entre plusieurs modes de customisation pour modifier la page.
L'une des solution d'affichage des options de customisation pour l'utilisateur consiste à encapsuler ensemble le contrôle WebPartManager et une collection de boutons (généralement de type LinkButton) dans un contrôle utilisateur qui sera ensuite placé dans la page maître pour fournir les options de customisation à toutes les pages du site. L'encapsulation de ces contrôles dans un contrôle utilisateur (que nous appellerons WebPartManagerPanel) est également utile si vous êtes amené à avoir plusieurs pages maîtres pour votre site Web, car vous pourrez ainsi bénéficier de mises en page différentes pour certains sous-ensembles de pages. La barre de menu de l'application de portail présentée plus haut à la figure 1 montre un exemple de contrôle utilisateur qui affiche le mode et la portée actuels du contrôle WebPartManager et fournit des boutons LinkButton qui font basculer le mode de la page vers l'un des modes d'édition pris en charge par le contrôle WebPartManager (contrôle utilisé par l'exemple d'application de portail).
Autre fonction utile à pourvoir dans votre contrôle WebPartManagerPanel : la possibilité d'afficher et de masquer de façon dynamique les modes d'affichage disponibles en fonction de l'utilisateur et de la page en cours. Vous pouvez demander les modes d'affichage pris en charge en consultant la collection SupportedDisplayModes du contrôle WebPartManager et utiliser ces informations pour activer ou désactiver l'option de menu qui expose ce mode. Par exemple, pour savoir si la page en cours prend en charge CatalogDisplayMode, vous devez procéder de la manière suivante :
if (WebPartManager1.SupportedDisplayModes.Contains(
WebPartManager.CatalogDisplayMode)) {
//enable catalog display mode LinkButton here...
}
Soulignons également que l'appel de ToggleScope échouera s'il est exécuté dans le contexte d'un utilisateur qui ne dispose pas des autorisations nécessaires. Il est judicieux de fournir du code qui demande la propriété CanEnterSharedScope exposée par la propriété Personalization des contrôles WebPartManager pour déterminer s'il faut masquer ou afficher l'élément d'interface utilisateur permettant à l'utilisateur de passer en portée partagée :
if (WebPartManager1.Personalization.CanEnterSharedScope) {
// display UI element that allows user to enter shared scope
}
Le contrôle utilisateur WebPartManagerPanel présenté dans l'exemple qui accompagne cet article contient une implémentation complète d'un panneau qui ajuste son affichage de façon dynamique en fonction de l'utilisateur actuel et des capacités de la page.
Contrôles utilisateurs en tant que composants WebPart
L'un des aspects frustrants de la création de composants WebPart dans Windows SharePoint Services est que vous devez entièrement programmer l'interface utilisateur de votre contrôle, sans l'aide d'un outil de conception. Étant donné que de nombreux composants WebPart sont des collections de contrôles serveur qui interagissent les uns avec les autres, il est dommage de ne pas pouvoir recourir au concepteur Visual Studio® pour créer ce type de composants. La solution évidente à ce problème est de permettre aux développeurs de créer des contrôles utilisateur ASP.NET et de les utiliser en tant que composants WebPart. (Un outil tiers appelé SmartPart prend en charge l'utilisation de contrôles utilisateur en tant que composants WebPart dans Windows SharePoint Services.)
Les composants WebPart ASP.NET 2.0 résolvent ce problème en permettant d'utiliser directement n'importe quel contrôle en tant que composant WebPart, sans modification ni encapsulation. Cela s'avère utile non seulement pour incorporer les contrôles utilisateur dans votre collection WebPart, mais aussi pour intégrer facilement les contrôles personnalisés que vous avez créés pour vos pages ASP.NET actuelles.
Le fonctionnement interne est le suivant : si un contrôle standard (non WebPart) est ajouté à un contrôle WebPartZone, cela génère un appel implicite vers la méthode WebPartManager.CreateWebPart qui alloue une instance de la classe GenericWebPart et l'initialise avec le contrôle qui a été ajouté. La classe GenericWebPart, dérivée de la classe de base WebPart, fournit des implémentations des propriétés WebPart principales. Lorsque la classe GenericWebPart est créée, elle ajoute le contrôle avec lequel elle a été initialisée en tant que contrôle enfant. Lors du processus de rendu, GenericWebPart ne renvoie rien à la mémoire tampon des réponses mais se contente de déléguer le rendu à son contrôle enfant, comme le font la plupart des contrôles composites. Résultat : vous pouvez ajouter n'importe quel contrôle à un contrôle WebPartZone d'une page et ça marche ! En guise d'illustration, la page suivante définit un contrôle WebPartZone avec un contrôle utilisateur et un contrôle Calendar standard, lesquels seront implicitement encapsulés dans la classe GenericWebPart au moment de la création :
‹%@ Register Src="webparts/CustomerList.ascx"
TagName="CustomerList" TagPrefix="Wingtip" %>
‹asp:WebPartManager ID=" WebPartManager1" runat="server" />
‹asp:WebPartZone ID="WebPartZone1" runat="server" HeaderText="Zone 1">
‹Wingtip:CustomerList runat="server" id="CustomerList" />
‹asp:Calendar runat="server" id="CustomerCalendar" />
‹/asp:WebPartZone>
Comme avec les composants WebPart standard, il est possible de créer dynamiquement des contrôles encapsulés dans une classe GenericWebPart. S'il s'agit d'un contrôle utilisateur, vous devez charger et créer de façon dynamique l'instance de contrôle utilisateur en appelant la méthode Page.LoadControl. Ensuite, vous devez attribuer explicitement un ID unique au contrôle. Puis, vous devez appeler la méthode CreateWebPart de l'objet WebPartManager pour créer une instance de la page GenericWebPart qui agira alors en tant que wrapper, encapsulant l'instance de contrôle utilisateur. Enfin, il vous faut utiliser la référence GenericWebPart renvoyée par l'appel vers CreateWebPart et la transmettre via un appel vers AddWebPart en spécifiant le contrôle WebPartZone dans lequel elle doit être ajoutée :
// create Web Part instance from User Control file Control uc = this.LoadControl(@"webparts\CompanyNews.ascx"); uc.ID = "wp2"; GenericWebPart wp2 = WebPartManager1.CreateWebPart(uc); WebPartManager1.AddWebPart(wp2, WebPartZone1, 1);

Figure 10 GenericWebPart
Le seul inconvénient de cette technique, c'est que vous perdez la possibilité de contrôler les fonctionnalités WebPart spécifiques du contrôle car c'est la classe GenericWebPart qui hérite du composant WebPart et non votre contrôle. Ce phénomène apparaît clairement lorsque vous exécutez une page contenant des contrôles encapsulés dans la classe GenericWebPart, car les titres de ces contrôles prennent par défaut la valeur Untitled (sans titre) et aucune icône ni description ne leur est associée, ce qui n'est pas habituel pour des composants WebPart. La figure 10 montre un exemple de contrôle utilisateur encapsulé par GenericWebPart, avec le titre par défaut (Untitled) et les icônes correspondantes.
L'une des façons de contourner ce problème consiste à ajouter un gestionnaire pour l'événement Init de votre contrôle utilisateur. Si votre contrôle est encapsulé dans GenericWebPart (ce que vous pouvez vérifier en demandant le type de votre propriété Parent), vous devez définir les attributs de la classe GenericWebPart de la façon suivante :
void Page_Init(object src, EventArgs e) {
GenericWebPart gwp = Parent as GenericWebPart;
if (gwp != null) {
gwp.Title = "My custom user control";
gwp.TitleIconImageUrl = @"~\img\ALLUSR.GIF";
gwp.CatalogIconImageUrl = @"~\img\ALLUSR.GIF";
}
}
Si vous exécutez la page à nouveau, tant que votre contrôle utilisateur sera encapsulé dans GenericWebPart, les modifications apportées aux propriétés du parent de GenericWebPart s'appliqueront au moment du rendu du composant WebPart contenant votre contrôle. Le contrôle utilisateur nouvellement attribué est présenté à la figure 11. Prenez note du titre et de l'icône.
Figure 11 Titre et icône
Il existe une autre solution intéressante : implémenter l'interface IWebPart directement dans votre classe de contrôle utilisateur. À première vue, cette solution ne semble pas très utile dans la mesure où le contrôle utilisateur n'est jamais interrogé directement concernant les propriétés WebPart, puisque ces détails sont gérés par la classe GenericWebPart. Heureusement, les concepteurs de la classe GenericWebPart ont anticipé ce besoin et ont implémenté les propriétés dans la classe GenericWebPart de telle sorte que la délégation au contrôle encapsulé s'effectue automatiquement si ce dernier implémente l'interface IWebPart.
Ainsi, pour customiser les fonctionnalités WebPart d'un contrôle utilisateur, il suffit d'implémenter l'interface IWebPart et de renseigner les sept propriétés qu'elle permet de définir. Le code présenté à la figure 12 montre un exemple de la classe codebehind pour un contrôle utilisateur permettant d'obtenir les mêmes résultats que précédemment en modifiant dynamiquement les propriétés GenericWebPart.
Vous pouvez même envisager de créer une autre classe de base pour vos contrôles utilisateurs. Cette classe dériverait de UserControl et implémenterait IWebPart ; elle pourrait ensuite être héritée par tous les contrôles utilisateur de votre portail. C'est ce que nous faisons dans l'exemple de solution portail qui accompagne cet article. Dans cette solution, vos contrôles utilisateur peuvent initialiser les propriétés qui les concernent dans leurs constructeurs et ne pas s'occuper du reste. La figure 13 illustre la solution d'une autre classe de base implémentant IWebPart pour les contrôles utilisateurs et d'une classe codebehind correspondante utilisée par un contrôle utilisateur pour définir les propriétés du titre et de l'icône.
Étant donné que les contrôles utilisateur présentent une telle flexibilité, peut-être vous demandez-vous quel est l'intérêt de créer un contrôle personnalisé alors qu'avec les contrôles utilisateur, vous pouvez, à l'aide du concepteur, personnaliser les fonctionnalités du WebPart ? Plusieurs raisons peuvent le justifier, à commencer par l'impossibilité d'ajouter des verbes personnalisés à un contrôle utilisateur. Vous devez effectuer une dérivation directe à partir de WebPart et remplacer la propriété Verbs. Vous pouvez aussi choisir d'implémenter IWebEditable dans votre contrôle.
L'autre raison, c'est que la portée intrinsèque des contrôles utilisateur se limite au répertoire de l'application. Il est impossible de partager l'implémentation d'un contrôle utilisateur entre plusieurs applications Web sans copier physiquement le fichier .ascx d'un projet à l'autre. D'autre part, les composants WebPart dérivés de la classe WebPart peuvent être compilés dans une DLL réutilisable et déployés globalement dans le GAC (Global Assembly Cache). De plus, avec les composants WebPart, vous pouvez écrire un concepteur personnalisé pour votre contrôle pour modifier son apparence par défaut dans Visual Studio et créer une icône à associer au composant WebPart lorsqu'il est placé dans la boîte à outils. La figure 14 présente une comparaison des fonctionnalités respectives des composants WebPart personnalisés et des contrôles utilisateurs pour permettre d'établir un choix.
Composants WebPart et fournisseurs de personnalisation
Les fournisseurs, nouvelle fonctionnalité d'ASP.NET 2.0, expliquent en grande partie la présence dans cette version d'une telle quantité de contrôles totalement fonctionnels dont la mise en œuvre exige peu de programmation, voire aucune. Le concept de base d'un fournisseur est de définir un jeu commun de tâches associées aux données pour une fonction particulière et de regrouper ces tâches dans une déclaration de classe abstraite héritant d'une classe ProviderBase commune. Pour les fonctionnalités de personnalisation étudiées dans cet article, les principales tâches associées aux données qui doivent être disponibles sont les suivantes :
| • | Enregistrement des propriétés WebPart et mise en page pour une page et un utilisateur particuliers. |
| • | Chargement des propriétés WebPart et mise en page pour une page et un utilisateur particuliers. |
| • | Enregistrement des propriétés WebPart générales et mise en page (customisation globale) pour une page particulière. |
| • | Chargement des propriétés WebPart générales et mise en page (customisation globale) pour une page particulière. |
| • | Réinitialisation des propriétés WebPart et mise en page à partir des propriétés par défaut pour une page et un utilisateur particuliers. |
| • | Réinitialisation des propriétés WebPart et mise en page à partir des propriétés par défaut (customisation globale) pour une page particulière. |

data source=.\SQLEXPRESS; Integrated Security=SSPI; AttachDBFilename=|DataDirectory|aspnetdb.mdf; User Instance=true
L'avantage d'utiliser une base de données basée sur un fichier SQL Server 2005 Express Edition, est qu'il est possible de la créer directement, sans que l'utilisateur n'ait à effectuer d'autres installations. Ainsi, vous pouvez créer un site complètement nouveau et commencer à utiliser les fonctions de personnalisation sans configurer de base de données : ça marche ! Votre première interaction avec le site générera un nouveau fichier aspnetdb.mdf dans le répertoire App_Data du site, qui sera initialisé avec les tables et procédures stockées nécessaires pour prendre en charge tous les fournisseurs par défaut.
Cette solution est adaptée aux petits sites peu évolutifs et qui n'ont pas besoin de prendre en charge de nombreux utilisateurs simultanés, mais pour les systèmes d'entreprise, il faudra stocker les données sur un serveur de base de données dédié et entièrement géré. Heureusement, il est facile de changer la base de données utilisée par SqlPersonalizationProvider. La classe SqlPersonalizationProvider est configurée pour initialiser la chaîne de connexion à LocalSqlServer, c'est-à-dire qu'elle recherche une entrée dans la section ‹connectionStrings› du fichier de configuration ayant le nom de LocalSqlServer et utilise la chaîne de connexion associée pour ouvrir une connexion à la base de données. Par défaut, la chaîne de connexion utilisée est celle présentée quelques paragraphes auparavant. L'écriture s'effectuera donc dans un fichier .mdf local SQL Server 2005 Express Edition. Pour modifier cela, vous devez d'abord effacer la collection de chaînes de connexion LocalSqlServer et réattribuer une nouvelle valeur de chaîne de connexion dans votre fichier Web.config (vous pouvez aussi effectuer ce changement dans le fichier Machine.config de votre ordinateur si vous souhaitez l'appliquer à tous les sites situés sur cette machine). Voici un exemple de fichier Web.config qui modifiera la base de données du fournisseur de façon à ce qu'elle pointe vers une instance SQL Server 2000 :
<configuration xmlns='http://schemas.microsoft.com/.NetConfiguration/V.2.0'>
<connectionStrings>
<clear />
<add name="LocalSqlServer" connectionString=
"server=.;integrated security=sspi;database=aspnetdb"/>
</connectionStrings›
...
</configuration>
Pour que cette modification fonctionne, il faut qu'il y ait sur le serveur local une base de donnée appelée aspnetdb, accompagnée des tables et procédures stockées requises par SqlPersonalizationProvider. Pour créer cette base de données, il existe un utilitaire fourni avec ASP.NET 2.0 appelé aspnet_regsql.exe. Lorsqu'il est exécuté avec les paramètres par défaut, il crée localement une base de données, appelée aspnetdb, contenant les tables nécessaires pour tous les fournisseurs. Vous pouvez également choisir d'installer les tables et les procédures stockées dans une base de données existante. Les noms de ces tables et procédures stockées portent tous le préfixe "aspnet". Les conflits avec des tables existantes sont donc peu probables.
Comme pour tous les fournisseurs dans ASP.NET 2.0, ce niveau d'indirection crée une architecture très flexible permettant de changer entièrement le magasin de données principal sans modifier les pages ni les composants WebPart qu'il contient.
Création de votre propre fournisseur de personnalisation
La possibilité de changer la chaîne de connexion pour le fournisseur de personnalisation vous octroie une certaine flexibilité, mais SqlPersonalizationProvider doit utiliser l'espace de noms System.Data.Sql.Client pour récupérer les données. Cela signifie que cette capacité se limite aux bases de données SqlServer. Si vous devez stocker votre personnalisation dans une base de données différente, voire dans un magasin de données complètement différent, vous devrez prendre les mesures nécessaires pour créer votre propre fournisseur de personnalisation. Heureusement, le gros du travail est déjà fait et facile à exploiter. Si vous voulez voir comment écrire des données de personnalisation dans un autre magasin de données, l'exemple de site portail qui accompagne cet article présente une implémentation complète d'un fournisseur de personnalisation spécialement adapté, appelé FileBasedPersonalizationProvider qui conserve toutes les données de personnalisation et de customisation dans des fichiers binaires locaux du répertoire App_Data de l'application. Les noms des fichiers binaires sont générés de façon unique pour chaque utilisateur et chemin d'accès. De même, il existe un seul fichier par chemin d'accès unique pour les paramètres utilisateur généraux.
Pour créer un fournisseur de personnalisation adapté à vos besoins, vous devez d'abord créer une nouvelle classe héritant de la classe de base PersonalizationProvider et remplacer toutes les méthodes abstraites héritées de la classe de base. La déclaration de classe présentée à la figure 17 explique comment procéder.
En fait, il existe deux méthodes réellement importantes à implémenter pour que votre fournisseur de personnalisation puisse commencer à fonctionner : LoadPersonalizationBlobs et SavePersonalizationBlob. Ces deux méthodes représentent la sérialisation binaire des données de personnalisation. Elles sont appelées par l'infrastructure de personnalisation pour récupérer les données lorsqu'une page est chargée et pour renvoyer les données écrites (généralement pour le compte d'un utilisateur particulier) en cas de modification des données dans la vue d'édition, de catalogue ou de création d'une page contenant des composants WebPart.
Dans l'exemple de code à télécharger, l'implémentation de SavePersonalizationBlob écrit les paramètres dataBlob dans un fichier dont le nom unique est basé sur le nom d'utilisateur et le chemin d'accès transmis. De même, l'implémentation de LoadPersonalizationBlobs recherche le fichier (en utilisant le même mécanisme de dénomination) et renvoie soit un Blob de données utilisateur, soit un Blob de données partagées. Par défaut, ces deux méthodes enregistrent ou chargent les données partagées si le paramètre userName entrant est null ; sinon, elles enregistrent ou chargent les données utilisateur. La figure 18 décrit l'implémentation de ces deux méthodes dans l'exemple de FileBasedPersonalizationProvider et présente deux méthodes d'assistance pour générer des noms de fichier uniques en fonction des informations sur le nom d'utilisateur et le chemin d'accès.
Une fois l'implémentation terminée, vous devez ajouter le fournisseur en tant que fournisseur de personnalisation enregistré dans la partie fournisseurs de la section de configuration de la personnalisation. Pour pouvoir l'utiliser réellement, vous devez le définir dans votre fichier Web.Config comme fournisseur par défaut pour la personnalisation. Voici un exemple expliquant comment faire de notre fournisseur personnalisé à base de fichiers le fournisseur par défaut de notre application :
‹webParts>›
‹personalization defaultProvider="FileBasedPersonalizationProvider"›
‹providers›
‹add name="FileBasedPersonalizationProvider"
type="Wingtip.Providers.FileBasedPersonalizationProvider" /›
‹/providers›
‹/personalization›
‹/webParts›
Si nous exécutons à nouveau notre site, toutes les données de personnalisation seront désormais stockées dans des fichiers binaires locaux. Il est clair que ce n'est pas une solution très évolutive, mais cet exemple donne une idée de la façon d'implémenter son propre fournisseur de personnalisation sur n'importe quel système d'arrière-guichet. La figure 19 décrit comment notre nouveau fournisseur se connecte à l'infrastructure WebPart générale.
Figure 19 Utilisation de FileBasedPersonalizationProvider
Pour aller plus loin
Vous avez pu constater qu'ASP.NET 2.0 et son nouveau jeu de contrôles WebPart rendaient moins fastidieuse la création d'applications de portail élaborées prenant en charge la customisation et la personnalisation. La caractéristique la plus étonnante de cette infrastructure est peut-être sa capacité de connexion à d'autres systèmes. Au lieu d'être liée à une implémentation de sérialisation et à un magasin de données particuliers, l'architecture du fournisseur facilite relativement l'écriture des données de personnalisation dans n'importe quel magasin de données principal utile à votre site. Alors n'hésitez pas à vous lancer dans la création de sites personnalisables avec les composants WebPart d'ASP.NET 2.0.
Si cet article vous a plu, vous pouvez en apprendre bien davantage sur l'utilisation des composants WebPart dans la création d'une application de portail ASP.NET 2.0. N'oubliez pas de télécharger l'exemple fourni sur le site Web MSDN Magazine. Vous trouverez plusieurs exemples à explorer dans les didacticiels présentés à la page ASP.NET 2.0 QuickStart tutorials (en anglais). Nous vous recommandons également de consulter le blog de Fredrik Normén (en anglais) qui présente plusieurs exemples intéressants d'utilisation de composants WebPart dans ASP.NET 2.0.