Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Thomas Lebrun

Tout sur WPF, LINQ, C# et .NET en général !

Actualités

[Silverlight] Développer des applications orientées “métier” avec Silverlight 3 et les .NET RIA Services !

Dévoilé au grand jour la semaine dernière, Silverlight 3 apporte son lot de nouveautés (support de l’accélération matérielle, binding sur des UIElement, Perspective 3D, etc…) pour toute la partie 3D.

A coté de cela, Microsoft a aussi dévoilé au grand jour le projet .NET RIA Services, dont je vais parler plus longuement dans ce post.

 

Présentation des .NET RIA Services:

Les .NET RIA Services sont en réalité un framework permettant le développement d’applications métier. Grâce à ce framework, vous allez pouvoir développer des applications pour lesquelles la logique métier est partagée entre le client et le serveur.

A bien y regarder, cela a l’air tout simple et c’est le cas ! Le développeur ajoute de la logique métier coté serveur et celle-ci est automatiquement partagée avec les clients qui sont liés au serveur. Maintenant, voyons que cela fonctionne, en partant d’un exemple simple…

Si vous voulez en savoir un peu plus, Brad Adams nous fait une petite présentation détaillée sur son blog: http://blogs.msdn.com/brada/archive/2009/03/19/what-is-net-ria-services.aspx

 

Création de l’application Silverlight:

Pour utiliser ce framework de développement d’applications métier, il suffit d’installer le fichier MSI que l’on peut trouver ici puis créer une nouvelle application Silverlight, dans Visual Studio 2008:

image

Visual Studio vous demande alors si vous souhaitez héberger votre application Silverlight dans un site Web: notez que la case “Link to ASP.NET Server Project” est coché:

image

Automatiquement, le projet Silverlight est créé et une référence vers les .NET RIA Services est ajoutée:

image

Voyons maintenant comment utiliser ce nouveau framework, à proprement parlé !

 

Création du domaine de service:

La première chose qu’il est nécessaire de faire, c’est mettre en place un domaine de service. Il s’agit d’une classe, qui hérite de DomainService, qui expose les entités et les opérations pour un domaine spécifique. C'est là que le développeur va ajouter la logique métier de l'application.

Avant de créer le domaine de service, il faut rajouter, coté serveur, une couche d’accès au données, en utilisant LINQ To SQL, Entity Framework ou n’importe qu’elle autre technique:

image

image

Maintenant, nous pouvons compiler notre projet et ajouter la couche de service. Pour cela, il convient d’ajouter (toujours coté serveur car je rappele que l’objectif de ce framework est de permettre de partager de la logique métier entre un servuer et des clients) un nouvel élément de type “Domain Service Class”:

image

Dès lors, Visual Studio va afficher une boite de dialogue contenant la liste des DataContext/ObjectContext qui sont trouvés dans le projet. Pour chacun de ces objets, il est possible d’inclure les différentes entités dans le domaine de service, en spécifiant si l’on veut ou non activer l’édition de l’entité (autrement dit si Visual Studio doit générer des méthodes d’ajout, suppression et édition) et si l’on veut générer des métadonnées.

image

Lorsque vous validez la boite de dialogue, Visual Studio génère le code de votre service de domaine:

 

namespace EmployeesViewer.Web

{

    using System;

    using System.Collections.Generic;

    using System.ComponentModel;

    using System.ComponentModel.DataAnnotations;

    using System.Linq;

    using System.Web.Ria;

    using System.Web.Ria.Data;

    using System.Web.DomainServices;

    using System.Data;

    using System.Web.DomainServices.LinqToEntities;

    using EmployeesViewer.Web.DAL;

 

 

    // Implements application logic using the NorthwindEntities context.

    // TODO: Add your application logic to these methods or in additional methods.

    [EnableClientAccess()]

    public class NorthwindDomainService : LinqToEntitiesDomainService<NorthwindEntities>

    {

 

        // TODO: Consider

        // 1. Adding parameters to this method and constraining returned results, and/or

        // 2. Adding query methods taking different parameters.

        public IQueryable<Employees> GetEmployees()

        {

            return this.Context.Employees;

        }

    }

}

Ce que l’on peut noter, c’est qu’il s’agit d’une classe qui hérite de LinqToEntitiesDomainService (car notre couche d’accès aux données se base sur Entity Framework). Bien sur, si l’on avait utiliser LINQ To SQL ou une autre technique, la classe de base aurait été différente. Ensuite, on peut voir l’attribut EnableClientAccess, qui permet d’indiquer que le domaine de service doit être accessible aux clients ! Enfin, on découvre une simple méthode qui se contente de renvoyer, à l’utilisateur, la liste des différents employés.

 

Accéder aux données depuis le client (Silverlight):

Notre domaine de service est maitenant terminé: il ne reste plus qu’a y accéder, coté client, pour récupérer les informations. Pour cela, vous n’avez rien à faire (entendez par là que vous n’avez pas besoin d’ajouter de référence ou autre). En effet, si vous vous souvenez bien, lors de la création de l’application Silverlight, nous avions coché la case “Link to ASP.NET Server Project” ce qui a eu pour effet de créer le lien entre notre serveur et le client Silverlight (si vous n’aviez pas coché cette case, vous pouvez changer cela dans les propriétés du projet Silverlight).

Ainsi, a chaque compilation de la solution, un proxy est généré, coté client, dans le répertoire Generated_Code (pour le visualiser, il vous faudra afficher tous les fichiers, dans l’explorateur de solutions de Visual Studio):

image

Ainsi, si l’on rajoute une simple grille, dans notre applications Silvelright:

image

Il suffit d’utiliser le “proxy” généré coté client pour accéder aux données:

image

C’est simple, rapide et la résultat est là:

image

 

Si on allait un peu plus loin:

Pour le moment, vous devez vous dire que c’est plutôt sympa mais qu’avec un service WCF standard, on aurait fait la même chose.

Voyons alors comment allez un peu plus loin… Nous allons pour cela dévouvrir un objet plutôt sympathique: le DomainDataSource. Il s’agit d’un objet qui vous permet, directement dans votre code XAML, de spécifier le domaine de service qui doit être utilisé comme source des données:

image

Cet objet dispose de propriétés intéressantes comme LoadMethodName, qui permet d’indiquer le nom de la méthode à appeler pour remplir la source de données, LoadSize qui indique combien d’éléments doivent-être chargés avant de refaire un échange avec le serveur, etc.

A partir de maintenant, plus besoin de passer par du code behind: un peu de binding, au niveau de la Datagrid, sur l’objet de type DomainDataSource et le tour est joué !

image

Notez l’utilisation de la propriété Data, sur le DomainDataSource, qui permet de récupérer les données chargées.

Il est également possible de regrouper les éléments, dans notre Datagrid. Pour cela, il convient d’ajouter un GroupDescriptor à notre DomainDataSource, en lui spécifiant la propriété selon laquelle on veut grouper (noter que riaData est le namespace XML pointant vers clr-namespace:System.Windows.Data;assembly=System.Windows.Ria.Controls)

image

Lors de l’exécution de l’application, le regroupement est effectué automatiquement sur la grille, sans que vous ayez besoin de modifier votre code:

image

Maintenant, il faut savoir que l’on dispose souvent de beaucoup d’informations à afficher sur l’écran et du coup, il est parfois plus sage de faire de la pagination et de ne chercher les données, sur le serveur, qu’à la demande de l’utilisateur. Et bien vous avez la possibilité d’utiliser le contrôle DataPager pour faire cela:

image

Comme vous pouvez le constater, celui-ci est très simple à utiliser: vous lui indiquer la source des données et combien d’enregistrement il doit afficher et il se charge du reste tout seul. Du coup, lorsque vous réexécutez votre application, le pager, qui affiche seulement 5 éléments (mais toujours groupés) apparait sur l’interface graphique:

image

Tout cela, c’est bien joli mais si on continue d’avoir beaucoup d’enregistrement, on aimerait bien pouvoir les filtrer pour n’afficher que ceux dont, le nom par exemple, commence par ce que l’utilsateur a saisi. Pour cela, on va commencer par rajouter une zone de texte (après tout, si on veut qeu l’utilisateur saisisse du texte, il lui faut une TextBox):

image

Ensuite, on va rajouter un filtre, sur notre DomainDataSource, via la collection FilterDescriptors:

image

Grâce à ce filtre, nous indiquons que dès que l’évènement TextChanged du contrôle nommé originFilterBox survient, nous voulons filtrer la source des données en ne prenant que les éléments dont la propriété LastName commence par le contenu de la propriété Text du contrôle. Ainsi, nous obtenons le résultat suivant:

image

Ainsi, sans avoir écrit la moindre ligne de code, nous avons pour le moment une interface Silverlight qui affiche de façon regroupé dans une grille, les éléments de la base de données, le tout avec une gestion de la pagination et du filtrage des résultats !

Une autre des fonctionnalités fortement appreciée, dans des scénarios d’applications métier, est la gestion des vues maitre/détails. Fort heureusement, on dispose à préent d’un contrôle DataForm qui permet d’afficher le détails d’un élément, l’affichage étant dynamique en fonction du type des propriétés utilisées:

image

Comme on peut le constater, il suffit d’indiquer la propriété CurrentItem du DataForm pour lui indiqué l’élément qu’il doit instrospecté afin d’en afficher le détail:

image

De plus, suivant les options/propriétés que vous spécifiez, certains boutons sont activés automatiquement ou non, comme par exemple les boutons d’éditions. D’ailleurs, lorsque le contrôle est en cours d’édition, il suffit de s’abonner à l’évènement ItemEditEnding pour soumettre les modifications à la base de données (avec, certes, un peu de code):

image

Ainsi, avec 5 lignes de code (coté client) et une grosse partie de XAML et databinding, on est en mesure de réaliser une application purement métier et cela, de façon très simple !

A présent, nous allons voir comment enrichir et/ou personnaliser nos entités métier, avec des métadonnées.

 

Gestion des métadonnées et implémentation de la validation

Lorsque nous avons généré notre domaine de service, nous avons spécifié que nous souhaitions avoir des métadonnées de générer, avec nos entités. C’est la raison pour laquelle Visual Studio nous a généré un fichier qui porte l’extension .metadata.cs (ou .metadata.vb si vous êtes développeur VB):

image

En regardant de plus prêt ce fichier, on se rend compte qu’il contient des classes partielles correspondant à vos différentes entités mais que ces classes contiennent elles-mêmes des classes de métadonnées et sont marquées avec l’attribut MetadataTypeAttribute:

image

Ces classes de métadonnées ne sont rien d’autres que des classes contenant des champs, représentant chacun une propriété de l’entité. Seulement, vous avez la possibilité de “personnaliser” ces métadonnées en rajoutant des attibuts qui vont vous servir à faire de la validation. Ainsi, vous disposez des attributs suivants:

  • Required: qui indique qu’une propriété est obligatoire
  • RegularExpression: qui indique qu’une propriété doit-être formatée suivant l’expression régulière indiquée
  • StringLength: qui permet de dire que la propriété doit avour une taille minimale et une taille maximale

De la même façon, vous avez la possibilité de créer vos propres attributs servant à la validation. Pour cela, il suffit de créer une classe qui hérite de la classe abstraite ValidationAttribute et de surcharger la méthode IsValid. Ainsi, on peut facilement se créer un attribut permettant de s’assurer qu’un champ ne doit pas être vide:

image

(Nous reviendrons sur l’attribut Shared dans la partie suivante).

A présent, vous pouvez utiliser votre attribut (ou les attributs disponibles de base) sur vos métadonnées:

image

Maintenant, vous n’avez… rien à faire ! Et oui, tout est géré par le framework .NET RIA Services qui se charge de notifier l’application client lorsqu’une règle de validation est enfreinte. Et, étant donné que le DataForm dispose d’un ErrorSummary, on se retrouve, automatiquement, avec une interface capable d’afficher les différentes erreurs qui sont survenues:

image

A noter que cette gestion des règles de validation est également valable sur le Datagrid:

image

Lorsque l’on regarde le code généré sur le client, on constate que les métadonnées sont correctement insérées au niveau des entités, ce qui vous permet donc d’étendre vos entités:

image

 

Partager du code

Une autre des fonctionnalités offertes par .NET RIA Services est la possibilité de partager du code entre le serveur et le client. Dans le cas précédent, j’ai écrit une classe StringIsNullOrEmptyAttribute. Or celle-ci réside sur le serveur et n’est, par défaut, pas accessible au client ce qui a pour effet de ne pas générer l’utilisation de l’attribut correspondant. Pourtant, cela fonctionne parfaitement grâce à 2 choses:

  • l’attribut Shared: qui indique qu’un élément doit-être partagé entre le serveur et le client
  • le nom du fichier qui contient les éléments que vous souhaitez partagé: il faut en effet que celui-ci se termine par l’extension .shared.cs (ou .shared.vb)

image

De cette façon, le code généré coté client prend en compte cet attibut et génère le code correspondant:

image

Donc, avec cet attribut et cette convention de nommage, on a la possibilité d’étendre nos entités en leur rajoutant des propriétés, des méthodes, etc. Ainsi, sur mon entité Employees, je peux tout à fait me rajouter une petite propriété:

image

Et automatiquement, coté client, la génération de la propriété est effectuée:

image

Et son utilisation, au travers des différents contrôles graphique, est automatique:

image

Le Datagrid et la DataForm ont en effet introspecté l’objet pour découvrir une nouvelle propriété: ils ont donc ajouté un nouveau champs, au niveau de l’interface graphique, pour afficher/modifier cette propriété. Bien sur, suivant le type de propriété (pour peu que ce soit une propriété de type simple comme string, int, bool, Datetime, etc…), le contrôle utilisé pour la représenter est différent ! Ainsi, si je rajoute une propriété de type bool:

image

La représentation graphique est adaptée:

image

C’est simple mais terriblement efficace: toute la logique de votre application est écrite coté serveur et récupérée, automatiquement, coté client !

Maintenant, il est tout de même temps de voir comment fonctionne tout cela car les fonctionnalités, c’est bien mais l’implémentation, c’est mieux Wink

 

Comment ca marche ?

Tout cela, c’est bien beau mais il faut reconnaitre que ce n’est pas magique ! En effet, observons les échanges entre le client et le serveur lorsque l’on charge l’application:

image

Après avoir téléchargé le fichier XAP contenant notre application Silverlight, on voit qu’une requête est effecté vers “DataService.axd/EmployeesViewer-Web-NorthwindDomainService/”.

Etant donné que l’on ne dipose pas de ce fichier DataService.axd, regardons ce que contient le fichier Web.config du serveur:

image

Et oui, comme vous pouvez le voir, DataService.axd n’est rien d’autre qu’un simple HttpHandler qui se charge de rediriger les appels à la classe DataServiceFactory. Pour le vérifier, un petit tour dans le proxy généré sur le poste client nous permet de visualiser ceci:

image

Ensuite nous pouvons voir, d’après l’URL générée, que le DomainDataSource, qui fait appel à la méthode LoadEmployees, a bien généré un appel à la méthode GetEmployees située sur le serveur, tout cela en utilisant, tout simplement, REST:

http://localhost:58649/ClientBin/DataService.axd/EmployeesViewer-Web-NorthwindDomainService/GetEmployees?$orderby=Country&$take=20

Comme vous pouvez vous en doutez, le $orderby est le paramètre utilisé pour faire le regroupement des éléments, au niveau du DomainDataSource et le $take correspond au paramètre LoadSize de ce même contrôle !

Dans le même genre, la possibilité de filtre du DomainDataSource passe, là encore, par une requête REST utilisant un $where:

http://localhost:58649/ClientBin/DataService.axd/EmployeesViewer-Web-NorthwindDomainService/GetEmployees?$where=(LastName.ToLower().StartsWith(%22f%22)%3d%3dTrue)&$orderby=Country&$take=20

 

Conclusions:

Bien que ce post soit relativement long, nous n’avons couvert ici qu’une partie des possibilités techniques offertes par Silverlight 3 et .NET RIA Services pour le développement d’applications orientées “métier”. En effet, pour bien faire, il aurait fallut voir la partie authentification, navigation entre les pages, etc. mais ce que nous pouvons déjà affirmé, c’est qu’il s’avère très (trop ?) simple de développer ce type d’application: toute la logique est développée sur le serveur, puis partagée avec les différens clients !

 

Liens:

Si vous désirez en savoir plus pour creuser un peu le sujet et voir les parties que je n’ai pas abordé, voici une liste de liens pour vous aider:

http://blogs.msdn.com/brada/archive/2009/03/17/mix09-building-amazing-business-applications-with-silverlight-3.aspx

http://blogs.msdn.com/brada/archive/2009/03/19/what-is-net-ria-services.aspx

http://www.nikhilk.net/RIA-Services-MIX09.aspx

http://code.msdn.microsoft.com/RiaServices

 

 

A+

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: dimanche 22 mars 2009 23:53 par Thomas LEBRUN
Classé sous : , ,

Commentaires

EliseD a dit :

Important : pour obtenir en détail tout ce qui est présenté ici, il y a un document de plus de 100 pages à lire absolument et qui présente tous ces points en détail : http://download.microsoft.com/download/F/B/8/FB8CA635-296B-487F-965C-8148F08B5319/riaservicesoverviewpreview.pdf

# mars 25, 2009 12:56

Antony a dit :

Bonjour,

Merci beaucoup pour cet article ! J'ai juste un petit souci étrange je n'ai pas accès au type "Domain Service Class" lorsque j'ajoute un nouvel élément à mon projet.

J'ai tenté de le créer "à la main" mais ça ne semble pas fonctionner. Cela peut-il venir que j'utilise une version express de visual studio Web Developer ??

Merci d'avance de votre aide.

# mars 30, 2009 16:07

Antony a dit :

Oui oui bien sûr toute la création du projet s'est déroulé correctement. J'ai bien ma référence "System.Windows.Ria". J'ai essayé de redémarrer mon pc sans résultat.

Peut-être dois-je réinstaller les RIA Services ? De plus, j'ai un visual studio 2008 fr d'installer + visual studio web developer 2008 englais + tous les outils pour silverlight 3 Beta. Le problème vient peut être également de là ?

# mars 30, 2009 16:33

Thomas LEBRUN a dit :

Je me demande si le pb ne vient pas du fait que tu utilises une version FR de VS 2008 car pour l'instant, les RIA Services ne sont dispos qu'en US.

Pas sur mais c'est une possibilité....

# mars 31, 2009 09:23

Antony a dit :

En effet le problème venait de là : j'ai créé une machine virtuelle installé que visual studio 2008 express englais et les RIA Services. Tout fonctionne correctement.

Merci beaucoup pour ton aide et bonne continuation !!

Antony

# mars 31, 2009 17:35

mschoum a dit :

Super article

J'ai cependant un petit probleme ... je veux simplement charger mes données (comme indiqué dans l'exemple ci-dessus) mais je n'ai pas l'équivalent de la méthode: context.LoadEmployee();

comment celle-ci est-elle générée ?

D'avance merci

# octobre 6, 2009 13:24

hakim a dit :

Merci beaucoup pour le partage...

Pourquoi pas un livre "Silverlight par la pratique" !

# septembre 29, 2010 17:44
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Etes-vous yOS compatible ? (2/3) : la nouvelle plateforme Yammer–Office 365–SharePoint par Le blog de Patrick [MVP SharePoint] le 04-22-2014, 09:27

- [ #Yammer ] [ #Office365 ] Quelques précisions sur l’activation de Yammer Entreprise par Le blog de Patrick [MVP SharePoint] le 04-22-2014, 09:03

- Après Montréal, ce sera Barcelone, rendez-vous à la European SharePoint Conference 2014 ! par Le blog de Patrick [MVP SharePoint] le 04-19-2014, 09:21

- Emportez votre sélection de la MSDN dans la poche ? par Blog de Jérémy Jeanson le 04-17-2014, 22:24

- [ #Office365 ] Pb de connexion du flux Yammer ajouté à un site SharePoint par Le blog de Patrick [MVP SharePoint] le 04-17-2014, 17:03

- NFluent & Data Annotations : coder ses propres assertions par Fathi Bellahcene le 04-17-2014, 16:54

- Installer un site ASP.net 32bits sur un serveur exécutant SharePoint 2013 par Blog de Jérémy Jeanson le 04-17-2014, 06:34

- [ SharePoint Summit Montréal 2014 ] Tests de montée en charge SharePoint par Le blog de Patrick [MVP SharePoint] le 04-16-2014, 20:44

- [ SharePoint Summit Montréal 2014 ] Bâtir un site web public avec Office 365 par Le blog de Patrick [MVP SharePoint] le 04-16-2014, 18:30

- Kinect + Speech Recognition + Eedomus = Dommy par Aurélien GALTIER le 04-16-2014, 17:17