Développer des applications .NET architecturées en composants

Retrouvez un résumé de cet article et bien d'autres dans le dossier "Composants" du magazine Programmez

Pour en savoir plus sur le développement par composants avec la fabrique logicielle CodeFluent, je vous invite à venir assister à la session de lancement de CodeFluent 2009 qui aura lieu lors de l’événement Microsoft Techdays à Paris le 10 février prochain à 14H30.

Développer des applications .NET architecturées en composants

La complexité des systèmes d’informations a toujours continué de croître et les technologies disponibles ne cessent jamais d’évoluer. Des nos jours, sur un projet de important, il n’est pas rare que les technologies utilisées évoluent de façon majeure avant même que le projet qui les utilise arrive à la fin.

Pour maitriser cette complexité, l’approche de développement basé sur des composants est devenue incontournable pour la réussite, la maintenabilité et surtout l’évolutivité d’un projet de développement.

Lors d’un atelier OOPSLA 2000 , Alan Cameron Wills avait utilisé une analogie avec les systèmes HiFi pour imaginer la structure que devrait avoir un logiciel basée sur des composants :

  • au plus haut niveau nous avons les appareils avec lesquels le consommateur interagit (lecteur CD, amplificateur, enceintes...) ainsi que les connecteurs et les interfaces standard permettant de les relier ;
  • à un niveau plus bas nous trouvons les sous-systèmes dont ces appareils sont composés (alimentation, unité de lecture CD, etc.) et un autre jeu de connecteurs et d’interfaces standardisées ;
  • en descendant encore d’un niveau, on trouve les circuits intégrés, les transistors, les diodes laser, etc. et à nouveau des connecteurs et des interfaces standard par le biais des quelles ces éléments sont connectés.

Cette petite illustration montre que la maturité actuelle atteinte dans l’industrie électronique est due à l’utilisation à chaque niveau des composants interconnectés de façon standard. De plus, comme dans beaucoup d’autres domaines matures, les composants utilisés sont produits de manière industrielle par des fabricants spécialisés et sont réutilisés pour assembler plusieurs types de produits.

Dans le domaine logiciel, cette maturité est plus difficile à atteindre car les composants du bas évoluent encore très fortement et les sous-systèmes deviennent rapidement obsolètes. Ceux qui conçoivent des applications au plus haut niveau sont donc partagés entre tirer parti d’un niveau intermédiaire structurellement obsolète ou revenir à un niveau plus bas avec l’assurance d’une difficulté à évoluer.

Pour conserver la similitude, l’approche de développement de composants proposée par CodeFluent consiste à construire des sous-systèmes à partir des besoins du haut niveau en les modélisant et assemblant de manière automatisée les éléments du niveau bas. On obtient ainsi une application au plus haut niveau découpée en composants (les sous-systèmes) qui peut évoluer au gré des innovations sur les couches basses car CodeFluent génère de nouveaux sous-systèmes à mesure que la technologie évolue au niveau le plus bas.

De manière concrète, CodeFluent se présente comme la première fabrique logicielle, de bout en bout, pilotée par le modèle pour l’environnement .NET.

Contact Manager

Nous allons prendre comme exemple une application de gestion de contacts dans laquelle, pour rester simple et pédagogique, nous n’utiliserons que deux entités métiers: User pour un utilisateur et Contact pour les informations de contact des utilisateurs.

Figure 1 : Les entités métier

Au niveau fonctionnel, notre problématique est donc relativement simple, nous allons gérer des utilisateurs et leurs informations de contact, même si l’approche est identique sur des modèles comprenant des centaines d’entités.

En ce qui concerne l’architecture, nous allons faire le choix d’une application Web ASP.NET qui persistera les données dans une base SQL Server. Notre application devra aussi s’intégrer dans le système informatique actuel de l’entreprise pour lequel le choix d’une architectures orientés services (SOA) a été effectué. Il nous est donc demandé d’exposer nos services métier en tant que services Web. Naturellement, nous allons utiliser WCF pour exposer nos services.

On peut résumer l’architecture de départ de notre application par le schéma suivant:

Figure 2: Architecture

Pour pouvoir utiliser la fabrique logicielle CodeFluent, nous devrons décrire nos entités ainsi que la configuration des producteurs de différents composants que nous souhaitons utiliser. A partir de ces informations, CodeFluent générera le code des composants de notre application.

Nous allons organiser le modèle en deux parties : la description de nos entités métier et la configuration des producteurs de composants. Ces deux parties seront référencées dans un fichier dit « pivot » qui sera donné en entrée de la fabrique logicielle CodeFluent.

Je vous propose de créer un répertoire de travail SoftFluent.Contacts.Design avec le sous-répertoire Model dans lequel nous allons mettre toutes les fichiers faisant partie du modèle. Pour l’instant, nous allons créer le fichier SoftFluent.Contacts.xml, qui sera donc le fichier pivot.

Le fichier pivot, point d’entrée du modèle

<cf:project xmlns:cf="http://www.softfluent.com/codefluent/2005/1"

                  defaultNamespace="SoftFluent.Contacts"

                  persistencePropertyNameFormat="{1}"

                  defaultKeyPropertyTypeName="int">

 

      <cf:import enabled="true" path="SoftFluent.Contacts.Entities.xml" />

      <cf:import enabled="true" path="SoftFluent.Contacts.Producers.xml" />

 

</cf:project>

En règle générale, ce fichier contient le paramétrage du projet CodeFluent ainsi qu'une référence vers chaque fichier XML faisant partie du modèle. Cette fonctionnalité d'import permet un découpage bien adapté à un mode de travail en équipe.

Chaque projet CodeFluent contient un nœud <cf:project> permettant de déclarer un paramétrage global à tout le projet. Les deux nœuds obligatoires sont xmlns:cf permettant de déclarer l'espace de nommage XML de CodeFluent et defaultNamespace permettant de déclarer l'espace de nommage racine de notre projet. Dans notre exemple, deux autres attributs ont été configurés: persistencePropertyNameFormat et defaultKeyPropertyTypeName.

persistencePropertyNameFormat={1} permet de spécifier au producteur SQL Server que le nom des colonnes qui vont être générées doivent être identiques aux noms des propriétés correspondantes dans le modèle.

defaultKeyPropertyTypeName="int" permet de préciser que le type par défaut des clés des entités métier sera un entier sur 32 bits (type « int »).

1. Les entités

Dans un fichier que nous allons nommer SoftFluent.Contacts.Entities.xml, nous allons décrire les entités métier de notre application :

<cf:project

      xmlns:cf=http://www.softfluent.com/codefluent/2005/1       defaultNamespace="SoftFluent.Contacts" >

 

<User>

            <Id />

            <Account collectionKey="true" />

            <Email unique="true" />

            <FirstName sortable="true" />

            <LastName />

            <Password />

            <BirthdayDate />

            <Photo typeName="photo" />

            <Contacts typeName="ContactCollection"/>

      </User>

 

      <Contact>

            <Id />

            <Email collectionKey="true" sortable="true" />

            <OtherEmail />

            <FirstName sortable="true"/>

            <LastName sortable="true"/>

            <BirthDate />

            <Title sortable="true"/>

            <OfficePhone sortable="true"/>

            <MobilePhone sortable="true"/>

            <OtherPhone />

            <HomePhone />

            <Fax />

            <Description maxLength="1000" />

            <Source typeName="ContactSource" />

            <User typeName="User" />

      </Contact>

 

      <ContactSourceEnum>

            <Undefined />

            <Email />

            <Phone />

            <BusinessEvent />

      </ContactSourceEnum>

 

</cf:project>

La première propriété des entités User et Contact est la propriété Id. Par défaut, CodeFluent suppose que la première propriété d’une entité représente la clé. Si son type n’est pas explicitement précisé, il sera déterminé à l’aide de l’attribut defaultKeyPropertyTypeName, dans notre exemple défini à int dans la configuration du projet. De nombreuses autres règles de déduction sont prises en compte par CodeFluent pour simplifier fortement la création d’un modèle métier. Un autre exemple, pour les propriétés dont le nom finit par Date, si le type de la propriété n’est pas explicitement précisé, le type sera déduit automatiquement par CodeFluent comme étant le type DateTime.

Vous aurez probablement remarqué que le type des propriétés Account, Email, FirstName, LastName et Password n’est pas explicitement déclaré. A partir de la deuxième propriété d’une entité, CodeFluent suppose par défaut que le type est une chaîne de caractères de longueur 256. Il est possible de modifier cette taille à l’aide de l‘attribut CodeFluent maxLength comme dans le cas de la propriété Description de l’entité Contact.

L’attribut unique utilisé sur la propriété Email de l’entité User sera pris en compte par le producteur SQL pour garantir l’unicité de cette propriété.
L’attribut collectionKey sera traité par le producteur CodeDom, en charge de la génération de la couche métier technique qui sera en C# dans notre exemple. En effet, CodeFluent générera un « indexeur » sur l’objet User permettant de rechercher un utilisateur donné au sein d’une collection d’utilisateurs via son compte de connexion, Account.

La définition de l’attribut sortable="true" sur une propriété a pour effet d’activer le tri sur cette propriété jusqu’au niveau de la base de données lors de la génération. Il est également possible de spécifier au niveau de l’entité que toutes les propriétés sont sortable.

Vous pouvez également remarquer l’utilisation du type « photo » sur la propriété Photo de l’entité User. La photo sera représentée sous la forme d’un BLOB ou BinaryLargeObject. Avec CodeFluent, il est très simple de déclarer des propriétés de type BLOB permettant ainsi le stockage de fichiers, photos, vidéos ou encore d’éléments audio. Par le simple fait d’utiliser un des types suivants : file, document, picture, photo, audio ou video dans le modèle, CodeFluent génère un code permettant de consommer un BLOB à l’aide des flux (en lecture et en écriture). Cela signifie que, de la couche service à la couche base de données en passant par la couche métier, les données seront transmises de manière optimale par petit tronçon de données. Le résultat est une limitation de l’ impact en terme de mémoire sur le serveur applicatif même si la donnée en transit pèse des centaines de Méga-octets ou de Giga-octets.

Comme l’utilisation des flux pour la gestion des types de données binaires, des nombreuses autres meilleures pratiques sont incorporées dans CodeFluent lors de la génération du code des composants.

La propriété Contacts représente la collection de contacts rattachée à l’entité User. Il a suffi de renseigner le type comme ContactCollection pour que cette propriété soit prise en compte comme une collection de contacts rattachés à l’entité User. C’est la manière de modéliser des relations 1/n avec CodeFluent, à condition que de l’autre côté de la relation, la relation retour soit déclarée comme c’est le cas dans notre exemple avec la propriété User de l’entité Contact.

Pour la propriété Source de l’entité contact, le type est une énumération. Il a suffit de suffixer le nom de l’énumération avec Enum dans le modèle afin pour la prise en compte du type ContactSource comme étant une énumération au sens C#.

2. Les producteurs

Avec CodeFluent, nous disposons de plusieurs producteurs spécialisés, fournis de base:

  • « Microsoft SQL Server ® producer », en charge avec la génération du modèle relationnel (tables, vues, index, …) et des procédures stockées dans une base SQL Server ;
  • le producteur CodeDom « Business Object Model », en charge de fabriquer la librairie des classes permettant de manipuler les entités métier;
  • le producteur « Service Object Model » (WCF) est disponible pour la génération des services et d’un proxy amélioré pour WCF;
  • « Microsoft Office ® Lists producer », permet d’accéder aux données métiers directement depuis une feuille Microsoft Excel ou une base de données Access 2007 et d’utiliser la synchronisation bidirectionnelle présente nativement dans Excel 2003 ou 2007, ou Access 2007;
  • « ASP.NET Web Site producer » en charge avec la génération des sites web ASP.NET;
  • « ASP.NET custom controls producer », fournit une librairie de contrôles « custom » ASP.NET utilisables pour le développement des applications Web;

La liste des producteurs n’étant pas exhaustive et s’enrichissant en permanence, je vous invite à vous rendre sur le site www.codefluent.com pour découvrir la totalité des producteurs disponibles. Un producteur spécial, appelé « Template Producer », est également disponible pour permettre l’utilisation des fichiers contenant des modèles de code source et étendre la génération avec d’autres types d’artefacts ou de code source. Nous avions ainsi illustré dans un article précédent comment générer du code pour plate-forme Java à l’aide de ce producteur. Notez qu’il est également possible de développer votre propre producteur spécifique avec CodeFluent, même si cette approche cible préférentiellement les développeurs chevronnés et les besoins très pointus.

Revenons à notre application de gestion de contacts pour configurer les producteurs dont nous avons besoin dans le deuxième fichier référencé dans notre modèle, SoftFluent.Contacts.Producers.xml.
Nous allons commencer par créer ce fichier en déclarant uniquement le nœud containeur <cf:project>.

<cf:project

xmlns:cf="http://www.softfluent.com/codefluent/2005/1"

      defaultNamespace="SoftFluent.Contacts">

</cf:project>

2.1. Le producteur SQL Server

Pour déclarer et configurer le producteur SQL Server de CodeFluent, qui aura en charge la génération de scripts contenant la création des tables, des vues, des contraintes d’intégrité et des procédures stockées, nous allons insérer, à l’intérieur du nœud <cf:project>, le contenu XML suivant :

<!-- configuration du producteur SQL -->

<cf:producer

typeName="CodeFluent.Producers.SqlServer.SqlServerProducer, CodeFluent.Producers.SqlServer">

      <cf:configuration

targetDirectory="..\..\{0}.Persistence"

updateDatabase="true"

connectionString="database=SoftFluent_Contacts;server=(local)\sqlexpress;Trusted_Connection=true"

/>

</cf:producer>

L’attribut targetDirectory spécifie le répertoire cible où seront déposés les fichiers générés. Notez que, dans un modèle CodeFluent, l’alias {0} sera remplacé par l’espace de nommage du projet (defaultNamespace) au moment de la génération.

L’attribut updateDatabase permet spécifier si l’ensemble des scripts SQL générés doivent être exécutés en temps réel sur la base de données sous-jacente. Si c’est le cas, il faut également spécifier une chaîne de connexion valide au travers de l’attribut connectionString. Cette chaîne servira uniquement lors de la génération et non au runtime.

2.2. Le producteur CodeDom - Business Object Model (BOM)

Ce producteur est en charge de la génération de la couche objet .NET de notre modèle d’entités métiers. Ce producteur est un des producteurs les plus importants de CodeFluent. Il n’est pas lié au producteur SQL Server vu ci-dessus car le code qu’il génère peut fonctionner avec toute base de données prenant en charge les procédures stockées (Oracle, etc…). De la même manière que pour le producteur SQL Server, pour le déclarer et le configurer nous allons insérer le contenu XML suivant a l’intérieur du nœud racine <cf:project> :

<!-- configuration du producter CodeDom - Business Object Model (BOM)-->

<cf:producer

typeName="CodeFluent.Producers.CodeDom.CodeDomProducer, CodeFluent.Producers.CodeDom">

      <cf:configuration

compile="false"

outputName="{0}.dll"

resourceFileFormat="resx"

runtimeResourceBaseName="{0}.{0}"

targetDirectory="..\..\{0}">       

      </cf:configuration>

</cf:producer>

 

Quelques attributs importants de ce producteur :

L’attribut compile spécifié si une compilation automatique doit être effectuée par CodeFluent à la fin de la génération. Nous allons compiler le code généré avec Microsoft Visual Studio et avons choisi donc de désactiver la compilation pilotée par CodeFluent.

L’attribut outputName permet de spécifier le nom du fichier « assembly » qui sera généré. La présence de cet attribut est obligatoire pour le producteur BOM, même si la compilation automatique est désactivée. Pour rappel, {0} est un alias vers le « defaultNamespace », qui est « SoftFluent.Contacts » dans notre exemple.

Avec resourceFileFormat="resx" nous spécifions que nous souhaitons générer des fichiers « resx » pour une utilisation sous Microsoft Visual Studio.

2.3 Le sous-producteur ServiceModel (WCF)

Afin de pouvoir exposer nos services avec WCF, nous allons déclarer l’utilisation du sous-producteur ServiceModel dans la configuration du producteur CodeDom (a l’intérieur du nœud <cf:configuration>) :

<!-- ce sous-producteur genére la couche serveur WCF ainsi que le modele Smart Client Object Model (SCOM) du proxy WCF client -->

<subProducer

typeName="CodeFluent.Producers.ServiceModel.ServiceProducer, CodeFluent.Producers.ServiceModel"

targetDirectory="..\..\{0}.Proxy"/>

 

Ce sous-producteur enrichit le code généré par le producteur BOM pour le rendre conforme avec WCF (Windows Communication Foundation) en créant donc une couche de service. Il nous génère également une bibliothèque proxy appelé « Smart Client Object Model » (SCOM) qui est une représentation quasi à l’identique du BOM et qui s’occupe de toute la tuyauterie entre la couche client et la couche serveur. C’est un proxy très amélioré, mais qui n’est pas obligatoire pour utiliser la couche de service ajoutée au BOM.

CodeFluent fournit également des modèles pour générer les fichiers de configuration nécessaires pour le serveur et le client WCF. Pour inclure ces fichiers de configuration WCF lors de la génération, nous allons utiliser le producteur générique TemplateProducer. Nous allons décrire sa configuration en rajoutant le contenu XML suivant a l’intérieur du nœud racine <cf:project> :

<!-- Template Producer for generating WCF configuratio files for server and client-->

<cf:producer

name="ServiceModelProducer"

typeName="CodeFluent.Producers.CodeDom.TemplateProducer, CodeFluent.Producers.CodeDom">

<cf:configuration

sourceDirectory="%CF_TEMPLATES_PATH%\ServiceModel"

targetDirectory="..\..\Generated\WCF_Sample\"

/>

</cf:producer>

2.4 Le producteur de site Web ASP.NET

Nous disposons également d’un producteur en charge de générer un site Web prêt à l’emploi permettant de manipuler les entités de notre modèle. Pour l’utiliser, nous allons le déclarer et le configurer à l’intérieur du nœud racine <cf:project> en rajoutant le contenu XML suivant :

<!-- WebSite Producer -->

<cf:producer

name="BaseWebSite"

typeName="CodeFluent.Producers.WebSite.WebSiteProducer, CodeFluent.Producers.WebSite">

<cf:configuration

deploy="true"

createVirtualRoot="false"

copyBinaries="false"    

sourceDirectories="%CF_TEMPLATES_PATH%\Templates\WebSite"

webSitePhysicalRootPath="..\..\{0}.BaseWebSite"

targetDirectory="..\..\{0}.BaseWebSite"

/>

</cf:producer>

Lors de la génération du site web, la fabrique utilisera le modèle disponible dans le répertoire d’installation de CodeFluent dans le sous répertoire Templates\WebSite. Souvent, on souhaite y apporter des modifications, sur la charte graphique par exemple. Dans ce cas, on peut créer une copie de ce dossier dans un autre répertoire sur laquelle on rajoute les modifications et utiliser le nouveau chemin dans l’attribut sourceDirectories.

Le site Web ASP.NET utilise des contrôles spécialisés qui sont fournis par le producteur « ASP.NET custom controls producer ». Pour l’inclure, nous allons le configurer a l’intérieur du nœud racine <cf:project> en rajoutant le contenu XML :

<!-- WebControls Producer-->

<cf:producer

typeName="CodeFluent.Producers.CodeDom.UI.Web.WebControlsProducer, CodeFluent.Producers.CodeDom">

<cf:configuration

            compile="false"

            outputName="{0}.Web.dll"

            targetBaseNamespace="{0}.Web"

            targetDirectory="..\..\{0}.Web" >

            <controlProducers>

                  <controlProducer typeName="Grid"

condition="BaseType.NodeType=&quot;Entity&quot;"/>

                  <controlProducer typeName="Form"

condition="BaseType.NodeType=&quot;Entity&quot;"/>

                  <controlProducer typeName="ListBox"

condition="BaseType.NodeType=&quot;Entity&quot;"/>

<controlProducer typeName="DropDownList"

condition="BaseType.NodeType=&quot;Entity&quot;"/>

                  <controlProducer typeName="RadioButtonList"

condition="BaseType.NodeType=&quot;Entity&quot;"/>

                  <controlProducer typeName="CheckBoxList"

condition="BaseType.NodeType=&quot;Entity&quot;"/>

                  <controlProducer typeName="DataSource"

                        condition="BaseType.NodeType=&quot;Entity&quot;"/>

                  <controlProducer typeName="Repeater"

condition="BaseType.NodeType=&quot;Entity&quot;"/>

                  <controlProducer typeName="ListBox"

                        condition="BaseType.NodeType=&quot;Enumeration&quot;"/>

                  <controlProducer typeName="DropDownList"

                        condition="BaseType.NodeType=&quot;Enumeration&quot; and BaseType.IsFlags=False"/>

                  <controlProducer typeName="RadioButtonList"

condition="BaseType.NodeType=&quot;Enumeration&quot; and BaseType.IsFlags=False"/>

                  <controlProducer typeName="CheckBoxList"

condition="BaseType.NodeType=&quot;Enumeration&quot; and BaseType.IsFlags=True"/>

</controlProducers>

</cf:configuration>

</cf:producer>

Comme vous pouvez facilement le deviner, ce producteur a en charge de générer des contrôles ASP.NET spécialisés (de type Grid, Form, ListBox, CheckBoxList, etc.) permettant de faciliter l’affichage et la saisie des objets de type complexe de l’application (entités, énumérations). On peut noter que la runtime web de CodeFluent (CodeFluent.Runtime.Web.dll) contient aussi un certain nombre de contrôles « custom » ASP.NET permettant l’affichage et la saisie d’un grand nombre de types .Net standards (ex : contrôle « BooleanControl » pour le type Boolean).

3. Fabriquer les composants

La fabrique logicielle CodeFluent est matérialisée par l'exécutable CodeFluent.Build.exe. Il reçoit en argument le nom du fichier « pivot » du modèle. Dans notre exemple, la commande à exécuter en ligne de commande est:

CodeFluent.Build.exe SoftFluent.Contacts.xml

Regardons de près ce que la fabrique CodeFluent nous a généré pour notre application.

Le producteur SQL Server nous a génèré le schéma relationnel complèt (tables, index, ...) ainsi que toutes les procédures stockées nécessaire pour la persistance de nos objets métier.

Figure 3 : Modèle relationnel

Au niveau des tables, remarquez l’ajout des champs permettant le suivi de chaque enregistrement (date de création/modification, utilisateur) et les champs liés au stockage de la photo de l’utilisateur.

Figure 4 : Les procédure stockées

En plus des procédures stockées de type CRUD de base (Create, Read, Update, Delete), veuillez remarquer la génération des procédures Contact_LoadByEmail et User_LoadByAccount. En effet, comme nous avons déclaré dans le modèle des entités les propriétés Email de l’entité Contact et Account de l’entité User comme étant des clés de collection, il est possible de retrouver des contacts a partir de l’adresse email associé ou des utilisateurs a partir de leur compte.
Notez également la procédure stockée User_SaveBlobChunkPhoto qui sera utilisée pour mettre à jour la photo de l’utilisateur par des tronçons de données, en utilisant les flux.

Tous les scripts de la base de données SQL Server sont déposés dans le répertoire configuré avec l’attribut targetDirectory au niveau du producteur SQL pour faciliter le déploiement sur un serveur de production ou leur intégration avec un gestionnaire de sources. Notez que CodeFluent crée aussi par défaut des scripts différentiels relativement à une base donnée de référence configurée dans le producteur.

Le producteur CodeDom nous produit la couche des objets métier comportant les classes User, Contact, les collections spécialisées correspondantes UserCollection et ContactCollection ainsi que l’énumération ContactSource. Ces classes disposent des méthodes qui permettent l’interrogation de la base de données, chaque entité étant responsable de sa persistance.

Une approche « lazy-loading » est utilisée pour les propriétés de type collection d’objets métier (dans le cas des relations entre entités) ou pour les propriétés basées sur des BLOB (photo, vidéo, audio, document, etc). Cela veut dire que la lecture dans la base relationnelle de ces données n’est effectuée qu’au moment ou ces propriétés sont directement accédées dans le code, pratique qui sert à diminuer de façon importante l’empreinte de l’application sur la mémoire.

Figure 5 : Les classes métier générées

Notez également le nombre important d’interfaces implémentées par les classes et leurs collections correspondantes. En particulier, toutes les interfaces nécessaires pour supporter le « data-binding » .NET sont implémentés par les classes correspondant aux objets métier et leurs collections spécialisées.

Le sous-producteur ServiceModel (WCF) produits les contrats de service et leurs implémentations ainsi que la libraire de classes proxy SCOM utilisable par un « smart » client.

Figure 6 : (WCF) Les contrats des services et leur implémentation

Remarquez que, pour chaque méthode de chargement de chaque entité, CodeFluent génère par défaut un équivalent permettant la pagination. Les noms de ces méthodes débutent toutes par Page. Par exemple, une méthode LoadAll est systématiquement générée pour chaque entité métier. Son équivalent en mode pagination est PageLoadAll.

Les classes proxy de la librairie SCOM ont été générées dans le namespace SoftFluent.Contacts.Proxy. Les classes proxy sont quasi identiques avec les classes du modèle objet (BOM). Toutes les méthodes des classes proxy interrogent en réalité le service WCF correspondant, encapsulé dans une classe interne WcfClient. Voici un extrait de la classe proxy Contact :

namespace SoftFluent.Contacts.Proxy

{

// CodeFluent generated (http://www.softfluent.com). Date: Tuesday, 30 December 2008 10:46.

      ...

public partial class Contact ...

{

...

[System.ComponentModel.DataObjectMethodAttribute(System.ComponentModel.DataObjectMethodType.Select, true)]

public static SoftFluent.Contacts.Proxy.Contact Load(int id)

{

if ((id == -1))

{

return null;

}

SoftFluent.Contacts.Proxy.Contact ret = SoftFluent.Contacts.Proxy.Contact.WcfClient.Current.Channel.Load(id);

return ret;

}

...

}

}


Un fichier « App.Config » avec la configuration WCF a été lui aussi générée dans le répertoire « ..\..\Generated\WCF_Sample\Client », comme spécifié par l’attribut targetDirectory du producteur TemplateProducer utilisé.
Tous les EndPoints WCF nécessaires pour l’hébergement et l’utilisation des services sont préconfigurés dans ce fichier. Bien entendu, si on le souhaite, on peut créer notre propre modèle de configuration WCF et l’utiliser avec le producteur TemplateProducer si on veut changer la configuration fournie par défaut.

Et finalement, le producteur WebSiteProducer nous a généré le code source complet du site web ASP.NET permettant de manipuler les entités de notre modèle.

Figure 7 : Le site web ASP.NET prêt a l’emploi

4. L’intégration du code métier spécifique

Jusqu'à présent nous avons vu comment fabriquer l’infrastructure complète avec tous les couches de notre application. Lors des développements d’un projet, nous avons clairement besoin de définir de nouvelles fonctionnalités, qu’il s’agisse d’implémenter des nouvelles méthodes d’accès aux données ou des règles métier.

CodeFluent comprend le langage CFQL (CodeFluent Query Language) permettant de définir très simplement de nouvelles méthodes qui seront générées sous forme de procédures stockées en base de données et sous forme de méthodes dans la couche .NET avec une cohérence globale. Par exemple, si on souhaite rajouter une méthode « NumberOfContacts » au niveau de la classe Contact nous allons la déclarer au niveau de l’entité Contact de la manière suivante :

<Contact>

...

<cf:method name="NumberOfContacts" body="count(User) where User=@User" />

...

</Contact>

Nous avons utilisé dans notre cas le verbe CFQL count, mais il en existe plusieurs autres comme load, loadone, delete et search. CFQL est un langage simple mais très puissant. Il permet de générer des procédures stockées SQL complexes, indépendamment du système de base de données cible, en partant d’une description CFQL simple.

Prenons un exemple différent. Si on souhaite rajouter une propriété FullName au niveau de l’entité Contact, calculée avec la concaténation du nom et prénom du contact, pour des besoins d’affichage par exemple, nous pouvons rajouter cella au niveau de l’entité Contact avec un « snippet » C#:

<Contact>

...

<FullName computed="true" />

<cf:snippet>

private void OnGetFullName()

{

if (_fullName != null)

return;

 

_fullName = FirstName + " " + LastName;

_fullName = _fullName.Trim();

if (string.IsNullOrEmpty(_fullName))

{

_fullName = Email;

return;

}

}

</cf:snippet>

...

</Contact>

On peut également implémenter toutes les règles métier spécifiques dans une librairie .Net externe ou dans des fichiers de classe partielle et de les utiliser dans les entités du modèle.

Quand les règles métier de l’application ont un cycle de vie beaucoup plus évolutif que celui de l’application, on peut également les externaliser sur des moteurs de règles comme « ILOG Rules for .NET ». CodeFluent incorpore également un moteur interne de règles qui permet d’externaliser des règles écrites en langage JScript ou VB Script (ou tout autre moteur de type ActiveX Scripting) dans un fichier externe à l’application.

Il est important de savoir que ces règles, indifféremment de la manière dont elles sont implémentées, seront considérées comme n’importe quelle autre méthode du modèle CodeFluent. Elles deviendront visibles donc aussi au niveau des services si le producteur ServiceModel (WCF) est actif et configuré dans le modèle. CodeFluent apporte ainsi la connectivité et la programmabilité sur les applications au niveau de chaque composant.

« High Cohesion, Low Coupling  »

Nous avons vu dans cet article comment développer une application Web ASP.NET a partir des composants produits par la fabrique logicielle CodeFluent selon un modèle décrivant les entités métier et les différents producteurs de composants nécessaires. Par la façon « standardisée » dont les composants correspondants aux différentes couches logiques d’une application ont été conçus, les composants fabriqués par CodeFluent peuvent s’assembler pour constituer des applications de n’importe quelle type d’architectur, comme:

  • « Client/Serveur » avec un client lourd basé sur les technologies WinForms ou Windows Presentation Foundation (WPF) ;
  • « Smart Client » avec la couche de présentation basée sur les technologies WinForms, Windows Presentation Foundation (WPF), Silverlight ou les forms « Smart Device » (PDA) ;
  • Web basé sur ASP.NET ;
  • Web basé sur la technologie de web parts de Microsoft Windows SharePoint Services 3.0 (WSS) ou Microsoft Office Sharepoint Server 2007 (MOSS) ;
  • et les architectures futures qui seront supportées par CodeFluent comme la plate-forme Azure ;

Figure 8 : Différentes types d’architectures cible

Pour la persistance des données on peut utiliser n’importe quel type de serveur de données supportant des procédures stockées. Dans la version actuelle, CodeFluent intègre un producteur spécialisé SQL Server prenant en charge les versions 2000, 2005 et 2008. Un producteur Oracle sera bientôt disponible cette année sachant que la portabilité de base de données est assurée par conception par l’approche CodeFluent.

La solution complète ainsi que des webcasts sur l’exemple dont nous avons parlé dans cet article sont également disponibles sur le site de CodeFluent : http://www.codefluent.com/Webcasts.aspx.

Pour en savoir plus sur le développement par composants avec la fabrique logicielle CodeFluent, je vous invite à venir assister à la session de lancement de CodeFluent 2009 qui aura lieu lors de l’événement Microsoft Techdays à Paris le 10 février prochain à 14H30.

[1] Conference “Object-Oriented Programming, Systems, Languages, and Applications”

[2] Cohésion forte, Couplage Faible

Catalin Manoliu, Consultant Senior SoftFluent

Back