Pierre Lagarde
Ecrire une extension à Community Starter Kit, Partie 1/2
Le but de ces deux articles est d'expliquer les principes de base pour développer son propre module sous Community Starter Kit
Par Pierre Lagarde publié le 18/06/2004 à 09:58, lu 10189 fois, 1 pages
Introduction
Le but de cet article et d'apprendre à développer de nouveaux modules pour le starter kit Community. En quelques mots, les starters kits sont des exemples de sites web fournis par Microsoft dans différents langages et pour deux plateformes de développement : Visual Studio et le SDK exploitable par WebMatrix.

Avec ces exemples de sites Web il est possible de se réapproprier les sources, les modifier, vendre des composants ou des modules, etc...

Ces articles expliquent :
  1. Comment créer un module simple à base de UserControl
  2. Comment créer une nouvelle WebBox
  3. Comment créer un nouveau vrai module Community
Pour plus d'info sur le Community Starter Kit je vous invite à aller voir le très bon article de Dain François Michaele de Supinfo sur comment l'installer, l'administrer et l'utiliser, c'est ici.
Créer le premier « custom module »
Créer un custom module pour Community est une des choses les plus simples. Car un custom module pour Community est simplement un UserControl.
Le custom module ne fait pas partie de manière intégrante du moteur de Community. Il ne sera pas inclus dans la recherche, il n'y aura pas possibilité d'être alerté en cas de changement, idem pour le tri automatique ou les commentaires.
Le custom module sera donc une sorte d'électron libre dans le site communautaire.
Le vrai module restera une solution plus complète et plus intégrée. Ce sujet sera traité dans un deuxième article.

Dans cet article nous allons créer un custom module qui va afficher la liste des membres de la communauté. Cette liste n'étant présente que dans l'administration du site, nous allons donc la rendre publique à la communauté.
Avant de démarrer
Le starter kit Community est basé sur l'approche composant. Tout élément dans Community est un contrôle serveur. Il faut savoir aussi que l'on peut appliquer des skins au StarterKit Community et pour implémenter cette fonctionnalité, les pages graphiques et le code behind sont séparés dans deux fichiers et dans des répertoires différents.Si nous prenons la page de recherche par exemple, le code behind est dans le répertoire :

Engine\Framework\Search\Content\Search.cs

Alors que le code graphique du user contrôle est dans le répertoire des skins :

Community\Common\Themes\Default\Skins\ContentSkins\Search_Search.ascx

Ou pour la skin 'Cruise' dans :

Community\Common\Themes\Cruise\Skins\ContentSkins\Search_Search.ascx

Nous remarquons que la page Search_Search.ascx est un UserContrôle et non une page aspx. En réalité tout le site ne repose que sur une seule page qui va charger dynamiquement chaque contrôle qui constitue sa page.

Pour résumer, le stater kit Community est construit avec une seule home page :

\Communities\Common\Themes\Default\Skins\PageSkins\Default.ascx

qui embarque des contrôles serveur qui génèrent un rendu html direct, ou qui utilisent d'autres UserContrôls pour afficher leur rendu. C'est cette dernière utilisation que l'on va exploiter pour ajouter un nouveau module au site.

Autre chose à savoir, la liste des utilisateurs est stockée en base de données dans la table Community_UsersLe contrôle serveur qui charge les UserContrôls nouvellement développé est dans :

Engine\Modules\CustomModules\Content\CustomModule.cs
namespace ASPNET.StarterKit.Communities {
    using System;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web;
    using ASPNET.StarterKit.Communities;
    //*********************************************************************
    //
    // CustomModule Class
    //
    // Displays a user control (.ascx file) in the content area of
    // a community page. 
    //
    //*********************************************************************

    [ParseChildren(true)]
    public class CustomModule : WebControl, INamingContainer {
        //*********************************************************************
        //
        // CreateChildControls Method
        //
        // Loads user control into Controls collection. The user control
        // must be located at the following path:
        //
        //   ~/Communities/[communityName]/CustomModules/[sectionName].ascx
        //
        //*********************************************************************
    
        protected override void CreateChildControls() {
            string skinFileName;
            Control skin;

            // Determine skin file name
            CommunityInfo objCommunityInfo = (CommunityInfo)HttpContext.Current.Items[ "CommunityInfo" ];
            SectionInfo objSectionInfo = (SectionInfo)HttpContext.Current.Items[ "SectionInfo" ];
            skinFileName = String.Format( "{0}/Communities/{1}/CustomModules/{2}.ascx", CommunityGlobals.AppPath, 
                                          objCommunityInfo.Name, objSectionInfo.Name );
            try {

                //Chargement du UserControl***********
                skin = Page.LoadControl(skinFileName);
                //************************************
                Controls.Add(skin);
            } 

            // Catch errors so they can be displayed.

            catch (HttpException he) {

                Controls.Add(new LiteralControl(he.GetHtmlErrorMessage()));
                Context.Trace.Warn( "community error","HttpException ::",he);
            }
            catch (System.IO.FileNotFoundException fnf) {
                string errorMessage = fnf.Message+" Not Found";
                Controls.Add( new LiteralControl(errorMessage) );
                Context.Trace.Warn("community error",errorMessage,fnf);
            }
            // guess that the file was not found?
            catch (Exception e)  {
                string errorMessage = "An unknown exception caused static page ("+skinFileName+") load abort -- see trace file for more info";

            Controls.Add( new LiteralControl( errorMessage ) );
            Context.Trace.Warn( "community error", errorMessage, e);
          }
       }
    }
}
Il suffit donc de créer un UserContrôl Membres.ascx et de le déclarer dans l'interface d'administration.
Créer le UserContrôle
Pour créer un UserContrôl, rien de plus simple, il suffit d'ouvrir le projet Community et d'aller dans le répertoire Communities\Community1\CustomModules et d'ajouter un UserControl







Il suffit de construire sa page graphiquement avec un joli DataGrid et de la remplir



Nous allons utiliser une procédure stockée, déjà existante dans le starter kit, qui est utilisée dans la partie administration du site Web et qui ramène tous les membres du site. « Community_AdminGetUsersForLetter »
if(!IsPostBack)
{
		SqlDataAdapter dadGet = new SqlDataAdapter( "Community_AdminGetUsersForLetter", CommunityGlobals.ConnectionString);
		dadGet.SelectCommand.CommandType = CommandType.StoredProcedure;
		dadGet.SelectCommand.Parameters.Add("@communityID", CommunityGlobals.CommunityID);
		dadGet.SelectCommand.Parameters.Add("@letter", "");
		dadGet.SelectCommand.Parameters.Add("@sortBy", "0");
		dadGet.SelectCommand.Parameters.Add("@orderBy", "0");
		DataSet dstUsers = new DataSet();
		dadGet.Fill(dstUsers);
		DataGrid1.DataSource = dstUsers;
		DataGrid1.DataBind();
}
Ce morceau de code peut être inséré à deux endroits :
  1. Ou directement avec le code html dans un tag script serveur, ce qui évitera la recompilation de la solution. La page sera compilée à la volée
    <%@ Control Language="c#"%>
    <%@ Import Namespace="System.Data" %>
    <%@ Import Namespace="System.Data.SqlClient" %>
    <%@ Import Namespace="ASPNET.StarterKit.Communities" %>
    
    <script runat="server">
    	void Page_Load()
    	{
    		//Code ...
    	}
    </script>
    
    <asp:DataGrid id="DataGrid1" runat="server" BorderColor="#999999" BorderStyle="None" BorderWidth="1px"
    	BackColor="White" CellPadding="3" GridLines="Vertical">
    	<FooterStyle ForeColor="Black" BackColor="#CCCCCC"></FooterStyle>
    	<SelectedItemStyle Font-Bold="True" ForeColor="White" BackColor="#008A8C"></SelectedItemStyle>
    	<AlternatingItemStyle BackColor="#DCDCDC"></AlternatingItemStyle>
    	<ItemStyle ForeColor="Black" BackColor="#EEEEEE"></ItemStyle>
    	<HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#000084"></HeaderStyle>
    	<PagerStyle HorizontalAlign="Center" ForeColor="Black" BackColor="#999999" Mode="NumericPages"></PagerStyle>
    </asp:DataGrid>
    
  2. Ou dans une page code behind dans l'objet Membres
    namespace ASPNET.StarterKit.Communities
    {
    	using System;
    	using System.Data;
    	using System.Data.SqlClient;
    	using System.Drawing;
    	using System.Web;
    	using System.Web.UI.WebControls;
    	using System.Web.UI.HtmlControls;
    
    	/// <summary>
    	///		Summary description for Membres.
    	/// </summary>
    	public class Membres : System.Web.UI.UserControl
    	{
    		protected System.Web.UI.WebControls.DataGrid DataGrid1;
    
    		private void Page_Load(object sender, System.EventArgs e)
    		{
    				// Code ....
    		}
    
    		#region Web Form Designer generated code
    		override protected void OnInit(EventArgs e)
    		{
    			//
    			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
    			//
    			InitializeComponent();
    			base.OnInit(e);
    		}
    		
    		/// <summary>
    		///		Required method for Designer support - do not modify
    		///		the contents of this method with the code editor.
    		/// </summary>
    		private void InitializeComponent()
    		{
    			this.Load += new System.EventHandler(this.Page_Load);
    
    		}
    		#endregion
    	}
    }
    
    Attention car quand on met en place la solution code behind, le wizard de création du UserContrôl place la page dans un mauvais namespace, il faut donc faire attention au namespace du côté code behind et du côté page html.
    namespace ASPNET.StarterKit.Communities
    {
    	...
    
    <%@ Control Language="c#" AutoEventWireup="false" Codebehind="Membres.ascx.cs" Inherits="ASPNET.StarterKit.Communities.Membres" 
        TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
    <asp:DataGrid id="DataGrid1" runat="server" BorderColor="#999999" BorderStyle="None" BorderWidth="1px"
        BackColor="White" CellPadding="3" GridLines="Vertical">
        <FooterStyle ForeColor="Black" BackColor="#CCCCCC"></FooterStyle>
        <SelectedItemStyle Font-Bold="True" ForeColor="White" BackColor="#008A8C"></SelectedItemStyle>
        <AlternatingItemStyle BackColor="#DCDCDC"></AlternatingItemStyle>
        <ItemStyle ForeColor="Black" BackColor="#EEEEEE"></ItemStyle>
        <HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#000084"></HeaderStyle>
        <PagerStyle HorizontalAlign="Center" ForeColor="Black" BackColor="#999999" Mode="NumericPages"></PagerStyle>
    </asp:DataGrid>
    
    Si on opte pour la solution code behind, il faut recompiler la solution. Ctrl+B
Installer le UserContrôl Membres
Maintenant que le User Contrôle est fini, il suffit de créer une nouvelle section dans l'administration qui va héberger ce UserContrôlAjouter une nouvelle section :



Le nom de la section correspond au nom du UserContrôl crééLe résultat est visible dans la section nouvellement créée



Créer une WebBox
Une des WebBox manquante au starter kit community est un WebBox qui affiche les événements à venir de la communauté.
L'idée de cette partie est de créer une telle WebBox.
Les WebBox sont stockés dans le répertoire Communities\Community1\WebBoxesNous allons écrire dans un premier temps une procédure stockée qui va ramener les événements courrant. Il existe déjà un objet conteneur qui va pouvoir accueillir le résultat provenant de la base de donnée EventInfo.cs dans Engine\Modules\Events\Components\EventInfo.cs
CREATE PROCEDURE Community_EventsGetCurrentEvents 
	@communityID int
--	@username NVarchar(50)
AS

DECLARE @currentDate DateTime
SET @currentDate = GetUtcDate()

DECLARE @currentMonth int
SET @currentMonth = DATEPART(month, @currentDate)

DECLARE @pageType int
SET @pageType = dbo.Community_GetPageTypeFromName('Event')

DECLARE @PageIndex TABLE
(
	PageID int
)

INSERT INTO @PageIndex(PageID)
	Select ContentPage_ID
	FROM Community_ContentPages
	WHERE 
		ContentPage_CommunityID = @communityID
	     AND ContentPage_PageType = @pageType
	     AND ContentPage_ModerationStatus = 1
	     AND ContentPage_DateVisible < @currentDate
	     AND ContentPage_SortOrder >= @currentDate
	     AND DATEPART(month, ContentPage_SortOrder) BETWEEN @currentMonth and @currentmonth + 1

SELECT 
	null Event_Link,
	null Event_FullDescription,
	Event_Location,
	Event_Speaker,
	Image_ID,
	Image_FileName,
	null, Event_SpeakerBiography,
	null Image_FileName,
	Content.*
FROM dbo.Community_GetContentItem(@communityID, NULL, @currentDate) Content
INNER join Community_Events With(nolock)
	ON ContentPage_ID = Event_ContentPageID
INNER JOIN @PageIndex PI 
	ON ContentPage_ID = PI.PageID
LEFT OUTER JOIN Community_SectionImages (nolock)
		ON ContentPage_ID = Image_ContentPageID

ORDER BY
	ContentPage_SortOrder 

RETURN
GO
Il ne reste plus qu'à créer un UserContrôl qui va afficher le résultat de cette procédure stockée.







Nous allons utiliser les contrôles serveur d'affichage « ContentList » pour afficher une liste de « EventContent »
<%@ import Namespace="ASPNET.StarterKit.Communities" %>
<%@ Register TagPrefix="community" Namespace="ASPNET.StarterKit.Communities" Assembly="ASPNET.StarterKit.Communities" %>
<%@ Control Language="c#" AutoEventWireup="false" Codebehind="WebBoxCurrentEvent.ascx.cs" 
Inherits="ASPNET.StarterKit.Communities.WebBoxCurrentEvent" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<%@ Outputcache duration="600" VaryByControl="Title"%>
<span class="webBox_TitleText" id="Title" runat="server"></span>
<br>
<community:ContentList id="ContentList" Runat="Server">
	<ItemTemplate>
		<li>
			<community:ItemTitleLink Runat="Server" />
			<br>
			<span class="WebBox_Content">
				Le <community:ItemEventDate Runat="Server" /><br>
				<community:ItemBriefDescription Runat="Server" />
			</span>
			<br>
			<br>
	</ItemTemplate>
</community:ContentList>
Il ne reste plus qu'à appeler la procédure stockée au chargement de la page et de binder l'ensemble des résultats sur le contrôle serveur d'affichage « ContentList ».
namespace ASPNET.StarterKit.Communities
{
	using System;
    using System.Data;
	using System.Data.SqlClient;
	using System.Drawing;
	using System.Web;
	using System.Web.UI.WebControls;
	using System.Web.UI.HtmlControls;
	using System.Collections;

	/// <summary>
	///		Summary description for WebBoxCurrentEvent.
	/// </summary>
	public class WebBoxCurrentEvent : System.Web.UI.UserControl
	{
		protected System.Web.UI.HtmlControls.HtmlGenericControl Title;
		protected ASPNET.StarterKit.Communities.ContentList ContentList;

		private ArrayList events = new ArrayList();

		private void Page_Load(object sender, System.EventArgs e)
		{
			//Appel de la procstok
			if (!Page.IsPostBack)
			{
				
				SqlConnection conn = new SqlConnection(CommunityGlobals.ConnectionString);
				SqlCommand comm = new SqlCommand("Community_EventsGetCurrentEvents", conn);
				comm.CommandType = CommandType.StoredProcedure;
				comm.Parameters.Add("@communityID", CommunityGlobals.CommunityID);
				conn.Open();
				SqlDataReader dr = comm.ExecuteReader();
				while(dr.Read())
				{
					events.Add(new Events.EventInfo(dr));
				}
				conn.Close();
				Title.InnerHtml = "Prochain vnements";
				ContentList.DataSource = events;
				ContentList.DataBind();
			}
		}

		#region Web Form Designer generated code
		override protected void OnInit(EventArgs e)
		{
			//
			// CODEGEN: This call is required by the ASP.NET Web Form Designer.
			//
			InitializeComponent();
			base.OnInit(e);
		}
		
		/// <summary>
		///		Required method for Designer support - do not modify
		///		the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.Load += new System.EventHandler(this.Page_Load);

		}
		#endregion
	}
}
Dans la partie administration du site, il maintenant possible d'enrichir les sections de cette nouvelle WebBox : WebBoxCurrentEvent (Community1)



Nous voyons bien ici que l'approche « composant serveur » choisie par Community StarterKit est extrêmement intéressante ; grâce à cette approche nous avons pu reconstruire un UserContrôl avec l'affichage d'une liste customisée sans aucune ligne de code. Nous avons juste affecté le DataSource et lancé le DataBind() sur ce contrôle.
Conclusion
La partie 2 de cet article sera consacrée au développement d'un module complet qui apparaît dans la liste des modules lorsqu'on crée une nouvelle section.
Si vous avez des idées pour un module en particulier, n'hésitez pas à poster un commentaire sur mon blog ici.
 
» Démarrer une discussion