Bewise

Nous développons... votre avance

Migration d'un projet Remoting Framework 2.0 vers Windows Communication Foundation (1/2)

SLF
13/06/2006 - Frédéric Colin
Télécharger la version Word
Télécharger les sources

1 Introduction

L'objectif de cet article en deux parties est de montrer la manière de passer d'une application utilisant le Remoting à une application utilisant Windows Communication Foundation (ex indigo). Dans une première partie je décrirai donc l'architecture de l’application développée et les raisons qui ont déterminé ses choix d'implémentation. Dans la seconde partie de l'article, je décrirai la nouvelle application à la sauce WCF.

Enjoy !

Les différents projets sont réalisés en Visual C#.NET, Framework 2.0.50727 et WinFX 3.0 Beta 2.

2 Quelques problématiques de l’application Remoting

Une des problématiques principale d'une application utilisant des composants distants via le Remoting est que le client a besoin de la définition des méthodes appelables sur un service distant (les langages .NET sont à typage fort). On pourrait finalement penser que ce n'est guère différent des applications COM+ d'antan que l'on déployait via le proxy généré par l'application COM+ (et qui déployait aussi la DLL ActiveX).

Pourtant ce n'est pas le cas. En effet, dans le monde .NET la manière d'instancier les composants distants est beaucoup plus riche qu'il n'y parait. En effet, on peut à loisir utiliser le mot clé « New », « Activator.CreateInstance() », « Activator.GetObject() ». La dernière manière de faire a pour avantage de ne déployer que le contrat du composant que l'on souhaite accéder. Comme vous vous en doutez, un contrat sera représenté par une Interface. C'est pourquoi l'application exemple ne référencera que les interfaces et pas directement les composants métiers.

Voici donc les quelques petites contraintes ajoutées dans cette appliquette :

  • Les différentes couches ne doivent échanger aucun objet technique, seulement des collections génériques typées
  • On ne déploie du côté client que les interfaces des composants accessibles en remoting
  • On doit facilement pouvoir switcher d'un appel CAO (Client Activated Object) à un appel SAO (Server Activated Object ou WellKnown)
  • On souhaite un paramétrage via un fichier de configuration

3 Description fonctionnelle de l’application

L'objectif fonctionnel est de récupérer la classique liste des employés de la base « Northwind » installée en standard avec SQL Server 2000.

Pour réaliser cet objectif et en tenant compte des contraintes précédentes, la solution .NET 2.0 est composée des projets suivants :

  • Data : couche simplissime chargée de l'accès aux données et de la constitution des collections génériques
  • Entities : permet de définir la structure des données échangées (collections et types élémentaires)
  • BusinessContracts : interfaces décrivant les contrats à implémenter par la couche métier
  • Business : la couche métier proprement dite implémentant les contrats décrits dans la couche BusinessContracts
  • Client : modeste application Windows Forms permettant d'afficher un bête jeux de données dans une grille récupérer via un composant accessible en Remoting
  • Service : application Web chargée de hoster les instances clientes

IIS hostera les composants et nous utiliserons un formatter binaire. Voici le schéma de référence des différents projets :

  • Data
    • Entities
  • BusinessContracts
    • Entities
  • Business
    • Entities
    • BusinessContracts
    • Data
  • Client
    • Entities
    • BusinessContracts
  • Service
    • Business
    • BusinessContracts
    • Data
  • Client
    • Entities
    • BusinessContracts

Voici le schéma de principe de l'application :

clip_image001

4 Paramétrage via un fichier de configuration

Le plus souple lorsque l'on souhaite travailler en Remoting est de passer par des fichiers de configuration. Deux fichiers de configuration seront nécessaires : l'un du côté du client, l'autre du côté du serveur qui va hoster les instances utilisateur. Examinons chacun d'entre-eux.

Voici pour la partie cliente :

<system.runtime.remoting> <application> <channels> <channel ref="http" useDefaultCredentials="true" port="0"> <clientProviders> <formatter ref="binary"/> </clientProviders> </channel> </channels> <client> <!-- SAO Factory for CAO objects --> <wellknown type="BusinessContracts.IFactory, BusinessContracts" url="http://localhost/Service/BusinessContracts.IFactory.rem" /> </client> <!-- (1) SAO types configuration --> <client> <wellknown type="BusinessContracts.IEmployee, BusinessContracts" url="http://localhost/Service/BusinessContracts.IEmployee.rem" /> </client> <!-- (2) CAO types configuration <client url="http://tazdevil/Service" > <activated type="BusinessContracts.IEmployee, BusinessContracts" /> </client> --> </application> </system.runtime.remoting>

Vous noterez plusieurs points :

1. le paramétrage du formatter à « Binary » dans la partie « clientProviders »

2. Pour la partie SAO : deux interfaces sont configurées. L'une pour l'accès au composant permettant de récupérer la liste des employés, l'autre permettant d'accéder à la fabrique de classe de type CAO. Je reviendrai sur ce point par la suite.

3. Si l'on regarde le paramétrage suivant : <wellknown type="BusinessContracts.IEmployee, BusinessContracts" url="http://localhost/Service/BusinessContracts.IEmployee.rem" />, vous noterez qu'a chaque fois que l'on veut récupérer une instance d'une classe implémentant l'interface BusinessContracts.IEmployee contenue dans l'assembly BusinessContracts.dll, il faut aller sur l'url "http://localhost/Service/" et plus précisément sur l'uri suivante BusinessContracts.IEmployee.rem correspondant au composant

4. Pour la partie CAO (commentée), l'objet implémentant l'interface BusinessContracts.IEmployee contenue dans l'assembly BusinessContracts.dll, à instancier le sera via l'url http://tazdevil/Service

Par conséquent dans ce petit exemple, pour passer du mode SAO au mode CAO, il suffit de décommenter la partie "(2)" et commenter la partie "(1)"

Voici donc pour la partie serveur :

<system.runtime.remoting> <application> <service> <wellknown mode="SingleCall" objectUri="BusinessContracts.IFactory.rem" type="Business.FactoryCAO, Business"/> <wellknown mode="SingleCall" objectUri="BusinessContracts.IEmployee.rem" type="Business.EmployeeService, Business"/> <activated type="Business.EmployeeService, Business"/> </service> <channels> <channel ref="http"/> </channels> </application> </system.runtime.remoting>

Vous noterez les points suivants :

1. la partie serveur est paramétrée de manière à gérer les demandes SAO sur l'URI BusinessContracts.IEmployee.rem et d'instancier Business.FactoryCAO de l'assembly Business.dll

2. la partie serveur est paramétrée de manière à gérer les demandes SAO sur l'URI BusinessContracts.IFactory.rem et d'instancier Business.EmployeeService de l'assembly Business.dll

3. En vous noterez que le type « Business.EmployeeService » peut-être aussi accessible en CAO via le tag « activated »

5 Mutualiser la création des instances de composants

Du fait du switch possible entre SAO et CAO, la création des instances n'est pas uniforme et doit être centralisée. En effet, comment gérer le switch SAO/CAO alors que « Activator.GetObject » ne fonctionne que pour les composants SAO. L'idée derrière tout ça est la mise en place d'une fabrique de classe chargée de tous ces aspects en fonction du paramétrage du fichier de configuration. De plus, nous verrons que l'utilisation des méthodes génériques peut s'avérer utile. Enfin dernier point l'utilisation de cette fabrique doit être la plus simple possible pour le développeur :

BusinessContracts.IEmployee service = Factory.GetInstance().GetObject<BusinessContracts.IEmployee>();

Pour arriver à cela, voici les éléments intéressants mis en oeuvre dans cette fabrique de classe appelée « Factory » dans le projet :

public T GetObject<T>() { if ( ! _types.ContainsKey(typeof(T)) ) throw new RemotingException("Unknown type!"); TypeEntry entr = _types[typeof(T)]; // Get SAO configured types WellKnownClientTypeEntry wct = entr as WellKnownClientTypeEntry; // Get CAO configured types ActivatedClientTypeEntry act = entr as ActivatedClientTypeEntry; // Check firstly for SAO types if (wct != null) return (T)Activator.GetObject(wct.ObjectType, wct.ObjectUrl); else { // Get the SAO factory for CAO types WellKnownClientTypeEntry entrCAOFactory = (WellKnownClientTypeEntry)_types[typeof(BusinessContracts.IFactory)]; BusinessContracts.IFactory fact = (BusinessContracts.IFactory)Activator.GetObject(entrCAOFactory.ObjectType, entrCAOFactory.ObjectUrl); return fact.GetObject<T>(); } }

Quelques éléments important sur cette fabrique de classe :

· Il s'agit d'un singleton dont l'instance est créée sur le constructeur statique

· Elle permet aussi de charger un cache (dictionnaire) des paramètres de configuration du fichier de configuration (membre _types). Ce cache contiendra indifféremment le paramétrage SAO (WellKnownClientTypeEntry) comme le paramétrage CAO (ActivatedClientTypeEntry). Par paramétrage, j'entends notamment le type et l'url.

· La méthode Getobject est générique et est chargée de la création de l'instance. Elle commence par vérifier si l'on est en mode SAO. Si c'est le cas, « Activator.GetObject() » suffit à créer l'instance distante et à générer le proxy. Sinon, on passe une fabrique de classe SAO pour les instances CAO

Comme vous pouvez le constater dans le code précédent, une fabrique d'instance CAO est réalisée à partir d'une classe SAO. Et c'est là que le bas blesse dans la solution mise en oeuvre. Le fait de ne posséder que les interfaces est très contraignant pour le mode CAO. L'implémentation de cette classe représente le talon d'Achille de ma solution puisque la fabrique d'instance CAO chaîne en dur les demandes de création d'instance des clients (classe « FactoryCAO » du projet Business).

Maintenant, il est vrai que conceptuellement parlant, peu de projets ont besoin de basculer leur couche métier de SAO vers CAO et inversement. Enfin, du point de vue de la montée en charge d'un serveur d'application, le mode SAO est préférable. Mais c'est une autre histoire !

6 Structuration des données échangées

Toute bonne architecture qui se respecte doit assurer la non adhérence des différentes couches avec des objets techniques. Pour assurer cela, la couche métier de ce petit exemple référence une assembly appelée entities. Cette dernière permet de regrouper les collections qui seront échangées.

clip_image002

Vous remarquerez sur le diagramme la présence de la classe générique « EntityCollection<T> ». Elle permettra de représenter nos collections fortement typées puisqu'elle hérite de « IList<T>. On pourrait à juste titre penser que cette dernière est inutile. Pourtant elle s'avèrera utile pour deux raisons :

· Il peut s'avérer très utile que ces collections implémentent l'interface IBindingList lors du databinding puisque c'est grâce à son événement « ListChanged » que les grilles pourront se rafraichir notamment.

· Lorsque vous choisissez le formatter SOAP pour la sérialisation d'une liste générique, cela ne fonctionne pas. En effet, il est dit dans la documentation à ce sujet : « The .NET Remoting technology supports both binary and SOAP serialization - that is, Remoting messages may be represented in a Microsoft-specific binary format or as SOAP XML. However, generic types (which are a new feature in .NET Framework 2.0) may only be used with binary serialization. The usage of generics with SOAP serialization is not supported, either through .NET Remoting or by using the SoapFormatter class directly ». En voilà une nouvelle, ça sent la classe dépréciée ça ! Il en va de même avec les types nullables. En effet, Microsoft indique que ce formatter n'a pas évolué avec.

En bref, si vous pensiez utiliser le SOAP FOrmatter pour accroitre l'interopérabilité de vos composants, préférez l'utilisation de Web Service "Basic Profile" en lieu et place du remoting HTTP + SoapFormatter qui reste une solution très propriétaire.

7 Conclusion

Il reste maintenant à réaliser la migration de ce petit exemple sur Windows Communication Foundation. Cette partie fera l'objet de l'article suivant : « Migration d'un projet Remoting Framework 2.0 vers Windows Communication Foundation 2/2 : la migration ».

> Tous les articles

Commentaires

aucun commentaire
Page 1/1
   
Connexion
  • Accueil
  • Plan du site
  • Contact
Bewise TV, Blog technique, Webcasts...

Votre carrière et nous

  • Nos offres
  • Votre candidature
Ignorer les liens de navigation > Accueil > Nos Métiers > Solutions Langages et Framework > Détail Article
Ignorer les liens de navigation
Nous
Nos Métiers
Vous Former
Nos Evénements
Nos Références
Nos Activités
Nos Certifications
Nos Chiffres
Le Groupe
Nos Partenaires
On Parle de Nous
Votre Carrière et Nous
Nous Contacter
Défiler vers le haut
Défiler vers le bas
Administration, Système et Communication
Architecture, Méthodes, Industrialisation
Décisionnel et Gestion des Données
Nouvelles Interfaces Utilisateurs
Portail et Travail Collaboratif
Solutions Langages et Framework
Solutions Web Avancées
Défiler vers le haut
Défiler vers le bas
Nos cours
Le Planning
Offres promotionnelles
Défiler vers le haut
Défiler vers le bas
TechDays'12
TechLunch
Windows 8 Camp
Défiler vers le haut
Défiler vers le bas
  • Infos légales
  • Lettre du Regional Director
  • Revue de presse