WPF MVVM une vraie Application

WPF MVVM Real-Time Trading Application

J'ai beaucoup étudié le modèle MVVM, les différents frameworks proposés, ce que l'on peut faire avec Prims. Je suis souvent tombé sur des exemples d'applications en Silverlight avec Prims ou pas.

Je cherchais une "vraie" application WPF utilisant le modèle MVVM quand je suis arrivé sur ce projet :

WPF / MVVM Real-Time Trading Application
Sa documentation.

WPF Real Time
Ses codes sources dans le Codeplex (no more codeplex !!!)

Requirements :
Visual Studio 2010
.NET Framework 4.0
Et ça fonctionne !
Aucune manipe de plus à faire pour exécuter le projet.

WPF MVVM Real-Time Trading Application est un projet brillant, l'auteur nous fait part de ses préoccupations de l'expression des besoins qui l'ont conduit à réaliser un tel développement. Alors comme tout est en anglais et bien je vais étudier ce projet et prendre ici quelques notes en français.

Spécifications

L'application doit répondre tout le temps, doit montrer en permanence les données très rapidement, ne doit jamais déraper ou se figer ne doit jamais planter ou s'exécuter en dehors de la mémoire.

C'est avec de telles spécifications que l'auteur Alexy Shelest va développer son produit.

Exigences ou besoins techniques

Application temps réel, la fiabilité, adaptabilité, l'extensibilité, l'évolutivité et la modularité (ce qui est la même chose, mais sonne mieux réunir dans une même phrase).

Prims

Effectivement les spécifications et les exigences techniques du projet font tout de suite penser à Prims et je lis avec intérêt les explications données par Alexy Shelest :

La modularité dans Prims est réalisée par le Bootstrapper qui s'occupe de charger les modules mais Alexy préfère largement la façon dont Marlon le réalise avec MEF dans le projet MeffedMVVM ...

Le découplage est réalisé par l'EventAggregator mais dans ce cas Alexy préfère le Mediator et le travail de Karl Shifflett tiré du travail de Marlon lui même tiré du travail de Josh Smith (et peut être pas dans cet ordre).

Dans Prims il y également le RegionAdpater et Unity qu'il ne va pas utiliser car en utilisant MEF pour instancier ses objets, il ne veut pas créer de longue chaîne de couplage comme peut le faire Unity. Il a l'idée que les ViewModels et les Services doivent être entièrement découplés et ne communiquer que par le Mediator quand ils s'enregistrent et diffusent des messages asynchrones.

Bref de Prims, il ne prend rien ! Nous sommes en Février 2012 et c'est justement à cette période que sort le Prims 4.1. Personnellement je trouve dommage de ne pas l'avoir utilisé d'autant que MEF est maintenant intégré dans Prism.

Pour aller plus loin


WCF Services par la pratique

Nous avons déjà vu quelques généralités concernant les WCF Services.

Pour passer à la pratique, je m'intéresse à l'exemple suivant :
http://msdn.microsoft.com/en-us/library/bb332338.aspx

Il s'agit de créer un Service Windows et d'y installer un WCF service, d'être capable de démarrer le Service Windows par programme, de créer un site web pour donner accès au WCF Service à "l'extérieur".

Vous y trouverez les codes sources à la rubrique Download the sample code.
Requirements :
Plateforme de développement : Windows 2003 Server
Visual Studio 2010
.NET Framework 4.0

NDL : J'utilise indifféremment le verbe hoster qui n'existe pas en français ou le verbe héberger.

Structure du projet Hosting and Consuming WCF Services :

Hosting and Consuming WCF Services Solution
Cette solution est composée des projets suivants :
  • ExchangeServiceIISHost : Site web d'hébergement du WCF Service
  • ExchangeService : Le WCF Service lui même
  • ExchangeServiceWindowsServiceHost : Le Service Windows qui hoste le WCF Service dans un Application Domain
  • SimpleClientWithProxy : Une simple console qui va utilisé le WCF Service à travers le Site Web
  • ExchangeServiceWindowsHostSetup : Projet d'installation permettant d'installer le service

Traduire la solution Visual Studio 2005 en Visual Studio 2010

C'est réalisé automatiquement sans souci en cliquant sur la solution : Practical.WCF.Chapter05.sln
La solution est ainsi traduite pour Visual Studio 2010.

Utiliser le .NET Framework 4.0 dans les projets de la solution

Afin de mettre à jour les références cassées des projets concernant les DLL :
System.Runtime.Serialization.dll
System.ServiceModel.dll

On utilise le framework 4.0 :
Bouton droit sur le projet -> Properties -> Application -> Target framework :

Modifier le Target Framework 4.0
Remplacer les références cassés par le références du .NET Framework 4.0 :
C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Runtime.Serialization.dll
Et :
C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.ServiceModel.dll

Dernière petite chose pour que la solution soit générée :
Dans :
\\WCF RIA Services\Hosting and Consuming WCF Services\ExchangeServiceIISHost\Web.config
Remplacez :

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
Par :
<configuration>

A ce stade votre solution doit se génèrer sans erreur.

Exécuter la Solution

Pour exécuter cette solution c'est à dire lancer la Console SimpleClientWithProxy car c'est elle qui dans son Program.cs, instancie un objet proxy pour accéder au WCF Service :
   TradeServiceClient proxy = new TradeServiceClient();

Afin de se brancher sur le WCF Service qui sera hosté par le Service Windows et sera mis à disposition des consommateurs par l'intermédiaire du site web, il faut encore :
  • Installer le WCF Service dans un Service Windows
  • Créer le site web

Installation du Service Windows qui hoste le WCF Service

Vous pouvez uiliser le projet d'installation ExchangeServiceWindowsHostSetup pour installer votre Service Windows en cliquant sur le .msi dans :
\\WCF RIA Services\Hosting and Consuming WCF
Services\ExchangeServiceWindowsHostSetup\Debug\ExchangeServiceWindowsHostSetup.msi

Vous aurez alors un petit souci :
Il faut mettre à jour la Launch Conditions du projet d'installation avec le Framework 4.0 :
Bouton droit sur le projet ExchangeServiceWindowsHostSetup -> View -> Launch Conditions :

Projet d'installation mise à jour des Launch Conditions
On voit que la version du Framework n'est pas à jour, choisissez le Framework 4.0 :

Projet d'installation, utiliser le framwork 4.0
Vous pouvez maintenant utiliser le projet d'install pour copier le Windows Service sur votre disque dur, il s'installe dans :
C:\Program Files\APress\QuickReturns ExchangeService Windows ServiceHost

En double cliquant sur l'install ExchangeServiceWindowsServiceHost.exe, j'obtiens le message suivant :

Installation du Service Windows, utiliser installutil.exe
On va donc utiliser l'outil installutil.exe du .NET Framework 4.0 pour installer notre Service Windows :
Ouvrir un fenêtre de command se placer dans le répertoire de installutil.exe :
C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319 et lancer la commande :
>installutil "C:\Program Files\APress\QuickReturns ExchangeService Windows
ServiceHost\ExchangeServiceWindowsServiceHost.exe"

Exécution de la commande d'installation du Service Windows qui hoste notre WCF Service :

Résultat de l'exécution de la commande installutil
Vérifier l'installation du Service Windows :
Démarrer -> Outils d'administration -> Gestion de l'ordinateur
On voit apparaître notre service Windows : QuickReturns Exchange Service :

Notre Service Windows est maintenant installé au sein de Windows
S'il n'est pas déjà démarrer, vous devez démarrer le service. Regardez dans la colonne "Etat" du service.

Installation du Site Web ExchangeServiceIISHost

Il s'agit de mettre à disposition notre WCF Service qui est maintenant hosté par un Service Windows à travers un site web.

Dans le fichier App.config de notre console SimpleClientWithProxy on regarde le endpoint :

            <endpoint address="http://localhost/ExchangeService/ExchangeService.svc" 
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ITradeService" 
contract="SimpleClientWithProxy.ExchangeService.ITradeService" 
name="BasicHttpBinding_ITradeService"/>

Il s'agit donc de créer un répertoire virtuel dans IIS qui va pointer directement sur le site web :
\\WCF RIA Services\Hosting and Consuming WCF Services\ExchangeServiceIISHost

Démarrer -> Outils d'administration -> Gestion de l'ordinateur -> Gestionnaire des services internet (IIS) -> Site Web -> Site par défaut -> Bouton droit -> Nouveau -> Répertoire virtuel :

Création du répertoire virtuel "ExchangeService"qui pointe sur ExchangeServiceIISHost
Configuration du site web :

Propriétés du répertoire virtuel
N'oublions pas que l'on travaille avec le framework 4.0 :

Configuration du répertoire virtuel pour utiliser le framework 4.0

Exécution de la console SimpleClientWithProxy

Notre console va t-elle s'exécuter ?
Visual Studio -> SimpleClientWithProxy -> Bouton droit -> Set as startup project -> F5 Run.

Il traîne une ligne à mettre en commentaire dans :
\\WCF RIA Services\Hosting and Consuming WCF 
Services\ExchangeServiceWindowsServiceHost\ExchangeWindowsService.cs

         // BRY_26022013 System.Diagnostics.Debugger.Break();
         ServiceHost host = new ServiceHost(typeof(TradeService));

N'oubliez pas de réinstaller le service en utilisant installutil avec l'option /u pour uninstall ...

Si vous n'avez pas correctement configuré votre site web, vous risquez encore d'obtenir l'erreur suivante :

Erreur de configuration du site web à l'exécution de la console
Et sinon, vous devez obtenir le résultat suivant :

Exécution correcte de la console SimpleClientWithProxy
ça fonctionne !

Conclusion

Certes l'exécution de la console n'est pas spectaculaire et pourtant elle met en oeuvre toute la chaîne d'exécution d'un WCF Service, hosté par un Service Windows installé dans les services de Windows et dont l'accès se fait par un Site Web installé derrière IIS 6.0.

Have fun !


HappyNet Silverlight Prism MVVM - Processus d'authentification

Comment permettre à un utilisateur de s'authentifier dans le projet HappyNet ?

HappyNet Connexion et Authentification
Entrons directement dans le vif du sujet, la partie UI est présente dans :
\\HappyNet-SL5\Client\Module\
Soat.HappyNet.Silverlight.Modules.Main\Views\LoginState\LoginStateView.xaml
<Button x:Name="LoginButton"
   cal:Click.Command="{Binding LoginCommand}"

Si l'on tape sur "Enter" le processus d'authentification démarre grâce au trigger :

                        <i:Interaction.Triggers>
                            <triggers:KeyTrigger Key="Enter">
                                <action:ExecuteCommandAction Command="{Binding LoginCommand}" />
                            </triggers:KeyTrigger>
                        </i:Interaction.Triggers>

Code de LoginCommand :
\\HappyNet-SL5\Client\Module\Soat.HappyNet.Silverlight.Modules.Main\Views\LoginState\ILoginStateViewModel.cs
\\HappyNet-SL5\Client\Module\Soat.HappyNet.Silverlight.Modules.Main\Views\LoginState\LoginStateViewModel.cs

public void InitializeCommands()
{
     this.LoginCommand = new DelegateCommand(this.OnLogin,
                () => !string.IsNullOrEmpty(this.UserName) && !string.IsNullOrEmpty(this.Password));

public void OnLogin()
{
            IsLoading = true;
            mainService.BeginLogin(this.UserName, this.Password, LoginCompleted);
}

\\HappyNet-SL5\Client\Module\Soat.HappyNet.Silverlight.Modules.Main\Services\MainService.cs

public void BeginLogin(string user, string password, ServiceCompleted<User> LoginCompleted)
{
            client.LoginAsync(user, password,
                new ServiceArgs<User>(LoginCompleted));
}

Autrement dit, on ne voit absolument pas dans quelle BD ni dans quelle table ni quel champ on utilise pour authentifier un utilisateur ... c'est de la magie encore une fois.

Authentification avec Silverlight et AdventureWorks

J'ai continué de chercher comment s'authentifier avec HappyNet et je suis tombé sur la page suivante :

On y voit d'ailleurs que l'on fait un "Add Exiting Item" de la Data Base AdventureWorks dans le répertoire App_Data ce qui est à mon sens une bonne chose pour le déploiement de l'application ...

Un problème avec Entity Framework et Available Context Class, la solution est Ici.





Silverlight Navigation and Authentification Application

Sur le sujet de l'authentification dans une application web, j'avais déjà écris beaucoup de choses et notamment développé un projet du Codeplex : http://loginmodule.codeplex.com/

Je suis donc curieux de découvrir l'état de l'art dans les applications Silverlight ... et je suis donc en train de lire les pages suivantes :

http://msdn.microsoft.com/fr-fr/library/ee942451(v=vs.91).aspx
Procédure pas à pas : Utilisation du service d'authentification avec une application de navigation Silverlight

Et la page :

http://msdn.microsoft.com/fr-fr/library/ee942449(v=vs.91).aspx
Procédure pas à pas : Utilisation du service d'authentification avec une application métier Silverlight

Pour constater, avec joie, qu'il n'y a pas grand chose de nouveau sous le soleil.

La première page "Utilisation du service d'authentification avec une application de navigation Silverlight" nous amène progressivement à la création de formulaires utilisateurs susceptibles de réaliser l'enregistrement et l'authentification de cet utilisateur à travers les WCF Ria Services, ce qui est déjà réalisé dans la deuxième page.

J'ai donc crée une Business Silverlight Application donc la structure est la suivante :

Silverlight Business Application Structure
Cette application Silverlight est hostée par une application web ASP.NET :

ASP.NET Application qui hoste le MyBusinessApplication.xap
Au passage, on peut noter que tout est déjà fait au niveau des WCF Ria Services pour qu'un utilisateur puisse s'enregistrer et s'authentifier au sein de l'application.

Et après avoir utilisé le formulaire d'enregistrement pour un nouvel utilisateur :

Siverlight WCF Ria Services enregistrement d'un nouvel utilisateur 
La fameuse base de donnée SQL Server : ASPNETDB.MDF apparaît comme par enchantement dans le répertoire App_Data de mon application ASP.NET Web :
\\Silverlight\MyBusinessApplication\MyBusinessApplication.Web\App_Data

Et je suis authentifié au sein de mon application Silverlight hostée par l'ASP.NET Web application :

Manager utilisateur créé et authentifié
Cette application met en oeuvre l'utilisation de l'objet Membership du namespace System.Web.Security afin de créer un nouvel utilisateur authentifié :

Dans :
\\Silverlight\MyBusinessApplication\MyBusinessApplication.Web\Services\UserRegistrationService.cs

    [EnableClientAccess]
    public class UserRegistrationService : DomainService

On utilise :
Membership.CreateUser(user.UserName, password, user.Email, user.Question, user.Answer, true, null, out createStatus);

Pour créer un nouvel utilisateur dans un rôle par défaut :
Roles.AddUserToRole(user.UserName, UserRegistrationService.DefaultRole);

Conclusion

Ces mécanismes d'enregistrement et d'authentification des utilisateurs sont toujours les mêmes, ils sont parfaitement maîtrisés et utilisés pour la gestion des rôles et des utilisateurs dans une application web. C'est par eux qu'ils faut impérativement passer et sinon pourquoi réinventer une roue qui existe déjà. C'est le problème que nous avons lorsque nous utilisons un projet comme HappyNet qui ne fonctionne pas de la même façon et du coup ne fonctionne pas du tout.





WCF Services Ressources

Voici des ressources utiles pour travailler avec Windows Communication Foundation c'est à dire les WCF Services.

Windows Communication Foundation

How to: Host a WCF Service in a Managed Application
http://msdn.microsoft.com/fr-fr/library/ms731758.aspx

Hosting and Consuming WCF Services
http://msdn.microsoft.com/en-us/library/bb332338.aspx#msdnwcfhc_topic3

L'adressage WCF en profondeur - Aaron Skonnard
http://msdn.microsoft.com/fr-fr/magazine/cc163412.aspx

Self-Hosted WCF Service
http://msdn.microsoft.com/fr-fr/library/ms750530.aspx

Exemples et documentation sur WCF

Getting Started :
http://msdn.microsoft.com/fr-fr/library/ms751519(v=vs.100).aspx

WCF and WF Samples
http://msdn.microsoft.com/fr-fr/library/dd483363(VS.100).aspx

Exemples Windows Communication Foundation (WCF)
http://msdn.microsoft.com/fr-fr/library/dd483346(v=vs.100).aspx

Download Samples

Windows Communication Foundation (WCF) and Windows Workflow Foundation (WF) Samples for .NET Framework 4 :
http://www.microsoft.com/en-us/download/details.aspx?id=21459

Extra-Tools for WCF Services

WCF service configuration editor

Que vous trouverez dans les raccourcis du menu Démarrer avec l'installation du SDK pour Visual Studio 2010.

Il vous permet de créer, de réparer des fichiers .config liés aux WCF Services. Ce sont des opérations délicates qu'il est un peu plus facile de mener avec cet outil.

WCF service configuration editor

 WCF Test Client

Comme sont nom l'indique, il permet de tester les WCF Services que vous avez installé. Il se comporte comme un client WCF, vous l'abonnez à vos services installés. Lors du développement de vos WCF Services, s'ils ne fonctionnent pas avec cet outil ce n'est pas la peine d'aller plus loin. Cet outil permet également de détecter des erreurs sous d'autres formes que les exceptions au moment du Debug.

Sont existence est parfois évoquée dans certains exemples par contre il n'est pas facile à trouver car il se trouve dans le répertoire suivant :

C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\WcfTestClient.exe

Et pour les machines 64bits :

C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\WcfTestClient.exe

Tools for WCF Services - WCF Test Client
Have Fun !

AdventureWorks for HappyNet v1.2

Le projet HappyNet possède un écueil de taille ; la BD AdventureWorks n'est pas installée et du coup il ne fonctionne pas !

On trouvera dans la documentation que l'on peut trouver une version de la BD Ici.

HappyNet v1.2 où est la base de donnée ?

HappyNet utilise Entity Framework pour fournir un modèle de la base AdventureWorks ce modèle est utilisé ensuite par les services WCF Services de la partie Silverlight.

Ce modèle entity se touve dans :
\\HappyNet v1.2 - SL5
\HappyNet-SL5
\Server\Core\Soat.HappyNet.Server.Entities\EntitiesModel.edmx

Mais que faire pour mettre en oeuvre la BD ?

Je parcours le projet et trouve dans le fichier :
\\HappyNet v1.2 - SL5\HappyNet-SL5\
Server\Core\Soat.HappyNet.Server.Entities\App.Config

Je trouve une ConnectionString :

 <!-- /!\ INSTALL NOTE /!\ Fill in the correct configuration to access your database -->
<add name="AdventureWorks2008" connectionString="Database=AdventureWorks_Data;Server=MyServer;Integrated Security=True;User ID=Username;Password=Password" providerName="System.Data.SqlClient" />

Cela ne risque pas de fonctionner !

Remarques : 

Je trouve le découpage du projet un peu curieux ...
Quelque chose de plus classique aurait été de mettre la BD dans le répertoire App_Data :
\HappyNet-SL5\Web\Soat.HappyNet.WebSite\App_Data\AdventureWorks_Data.mdf

Et donc le modèle entity dans Soat.HappyNet.WebSite qui est l'application Web qui hoste le .xap.

Autre remarque au niveau découpage du projet, le code behind des services comme par exemple :
HappyNet-SL5\Web\Soat.HappyNet.WebSite\Services\HumanResourcesService.svc
Se trouve dans :
\HappyNet-SL5\Server\Service\Soat.HappyNet.Server.Services.HumanResources\ServiceLayer\HumanResourcesService.cs

Dans HappyNet on trouve dans le projet Soat.HappyNet.Server.Entities
\HappyNet-SL5\Server\Core\Soat.HappyNet.Server.Entities\App.Config

<add name="AdventureWorksModel" connectionString="metadata=res://*/EntitiesModel.csdl|res://*/EntitiesModel.ssdl|res://*/EntitiesModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=TRAININGSQL;Initial Catalog=AdventureWorks2008;Persist Security Info=True;User ID=Silverlight;Password=pouetpouet!;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />

Cela ne risque pas de fonctionner sur votre machine de développement !

Trouver la bonne chaîne de connexion

Astuce pour trouver la bonne chaîne de connexion :
Sur le projet :
\HappyNet v1.2 - SL5\HappyNet-SL5\Server\Core\Soat.HappyNet.Server.Entities
Je fais :
Add->NewItem->ADO Entity Data Model->que je nomme AdventureWorks
Et je regarde regarde la chaîne de connexion générée, je trouve:

<add name="AdventureWorksModel" connectionString="metadata=res://*/EntitiesModel.csdl|res://*/EntitiesModel.ssdl|res://*/EntitiesModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.\SQLEXPRESS;attachdbfilename=|DataDirectory|\AdventureWorks_Data.mdf;integrated security=True;connect timeout=30;user instance=True;multipleactiveresultsets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />

Cela me parait être mieux.

Malgré tout à l'exécution j'aurais toujours un "Acces Denied" !

Autres tentatives

J'ai essayé de générer la BD à partir du Modèle Entity, cela ne fonctionne pas non plus ... Il manque alors certaines procédures stockées ...
Je ne trouve pas le moyen d'exécuter la procédure de création d'un utilisateur ...
Lorsque je tente de me connecter j'obtients l'erreur suivante :

{ExceptionDetail, probablement créé par IncludeExceptionDetailInFaults=true, dont la valeur est :

System.Data.EntityException: The underlying provider failed on Open. 
----> System.Data.SqlClient.SqlException: Unable to open the physical file 
"HappyNet-SL5\Web\Soat.HappyNet.WebSite\App_Data\AdventureWorks_Data.mdf". 
Operating system error 5: "5(Accès refusé.)".

An attempt to attach an auto-named database for file 
\\HappyNet-SL5\Web\Soat.HappyNet.WebSite\App_Data\AdventureWorks_Data.mdf failed. 
A database with the same name exists, or specified file cannot be opened, or it is located on UNC share.

Sympathique comme erreur est ce que cela vient du répertoire où j'ai positionné la BD ?
Si j'essaye de la mettre dans :
\HappyNet-SL5\Server\Core\Soat.HappyNet.Server.Entities
Etant donné que d'autres projets font référence à celui-ci la BD est copiée autant de fois dans Bin et Debug et mon disque stature rapidement ...

J'arrête de perdre mon temps ...

Accès à la démonstration en ligne

A l'adresse suivante :

En cliquant sur le bouton "Ressources Humaines", on obtient le message "Access Denied" c'est rassurant :

HappyNet : Acces Denied
Vous avez certainement lu quelque part que l'on peut s'identifier avec demo/demo et ça fonctionne en effet :

HappyNet : Accès aux Ressources Humaines
Exécution dans chrome, accès à la partie Boutique :

HappyNet : Accès à la Boutique
Ca fonctionne ! Et Silverlight v5.0 est bien compatible avec Chrome.

Comment créer et authentifier un utilisateur ...

Conclusions

Oui c'est souvent le cas des projets Open Sources du Codeplex et surtout si vous avez derrière une société à but non lucratif, la Base de Donnée est très difficile à installer à configurée et souvent la "vraie" bd du projet n'est pas accessible facilement . Il faudra certainement faire appelle à leurs services moyennant quelques finances mais après tout c'est le jeux ...

Vous aurez remarqué au passage l'extrême lenteur d'exécution de ce type d'application, si vous avez une machine un peu ancienne, elle sera à genoux !

Je suis surpris de l'exécution dans le navigateur Chrome mais c'est une très bonne surprise. Après la disparition de Flash aucune nouvelles plateformes ne voulant plus installer son plug-in, on peut penser que les applications Silverlight ont encore un peu d'avenir.

WCF Services Généralités

Personnellement, j'ai déjà utilisé les WCF Services, c'est l'évolution permettant une meilleur interopérabilité entre différentes applications c'est donc un élément clef de l'architecture logicielle. Je ne prends note ici que des points qui m'intéressent particulièrement.

Web Services, Service References, c'est forcément un peu confus, disons que les Web Services permettent la communication entre applications web tandis que les Service References possède plusieurs Endpoints permettant la communication entre applications hétérogènes.

Comprendre les Application Domains .NET

Du code managé peut être hosté par un Service Windows (Process). Le CLR isole le code managé en créant des partitions logiques séparées à l'intérieur du Service Windows que l'on appelle Application Domains. Un seul Process peut contenir plusieurs Application Domains. Chaque Domaine d'Application hoste des parties distinctes de code encapsulé dans des Assemblies.

Cette capacité d'un Service Windows de hoster des Application Domains possède plusieurs avantages :
  • Les Application Domains ont un impacte neutre sur le système d'exploitation et sur la plateforme .NET car elle créée une abstraction de la notion d'exécutable ou de librairie. 
  • Les Application Domains peuvent être contrôlées à loisir chargées et déchargées.
  • Les différents Application Domains qui existe au sein d'un Process sont indépendantes les unes des autres et reste fonctionnelle lorsque l'une se plante.

Hébergement d'un service WCF

WCF à besoin d'au moins un Domaine d'Application hosté dans un Service Windows.

Un service WCF peut être hébergé soit dans une application cliente, Console ou Winform ou Service Windows soit dans une application ASP.NET sur un serveur IIS dans ce cas on pourra utiliser les protocoles http/https pour communiquer avec le service.

Lors du choix du host certaine considérations sont à prendre en compte :
  • Disponibilité : Quand souhaitez vous que votre service soit joignable ?
  • Fiabilité : Que se passe t-il si votre service s'arrête, est ce que cela affecte les autres consommateurs ?
  • Versioning : Devez-vous supporter des versions différentes et anciennes de votre service ? Savez vous qui consomme votre service ?
  • Déploiement : Quel est votre modèle de déploiement ? Installez-vous avec un packages de déploiement d'installation de Microsoft et Visual studio, ou un xcopy est-il suffisant ?
  • État : Vos services sont-ils sans état ? Ou avez-vous besoin de l'état de session dans votre service ?
Remarque : Le modèle de programmation WCF est agnostique de l'endroit où il est en cours d'exécution, passer à un autre hôte est toujours possible plus tard, et cela signifie que vous n'aurez pas à modifier  votre implémentation de service. En règle générale, vous commencerez avec un scénario auto-hébergé dans une application console pour test-drive et prototyper vos services.

Service WCF qui se hoste lui même

Pour qu'un service se hoste lui-même deux choses sont nécessaires, le runtime WCF et une application .NET managée dans laquelle vous hébergée le ServiceHost et qui doit contenir le code pour démarrer et stopper le service.

Pour aller plus loin, je vous propose l'article suivant : WCF Services par la pratique

Vous pouvez également lire : WCF Services Ressources
Les ressources nécessaires pour travailler avec WCF.


Expression Blend SDK for .NET and Silverlight

J'ai installé Visual Studio 2010 en version anglaise alors j'installe également le Blend SDK en version anglaise :

Microsoft Expression Blend Software Development Kit (SDK) for .NET 4


Il me semble qu'il y a quelques DLL indispensables au fonctionnement de MVVM dans ce SDK
C:\Program Files\Microsoft SDKs\Expression\Blend\.NETFramework\v4.0\Libraries
Microsoft.Expression.Interactions.dll
System.Windows.Interactivity.dll

On va avoir pas mal de souci avec ces deux DLLs et en effet, elles sont parfaitement indispensables.
Et ce que je trouve le plus fou, je vais vous le dire, elles sont différentes pour WPF et pour Silverlight !?

Petite photo avant d'intaller Blend SDK pour SL :

Installation du Microsoft Expression Blend Software Development Kit (SDK) for .NET 4

Microsoft Expression Blend Software Development Kit (SDK) for Silverlight 4


Effectivement après l'installation de Blend pour Silverlight 4 :

Installation Microsoft Expression Blend Software Development Kit (SDK) for Silverlight 4
Permettez moi d'être surpris par, à nouveau ces différences de framework entre .NET 4.0 et Silverlight 4 surtout si elles se font au niveau de Blend :

Microsoft.Expression.Interactions.dll pour .NET 4.0

Microsoft.Expression.Interactions.dll pour Silverlight 4.0
Dans l'Object Browser, on ne verra pas de différences ... Les différences sont ailleurs.

Microsoft Expression Blend Software Development Kit (SDK) for Silverlight 5

Et bien oui, nous sommes en 2013 et il existe une version de Silverlight 5 depuis le 12/5/2011. Et même si l'on dit que bientôt Silverlight va disparaitre ... snif, la version 5 de Silverlight est maintenant la plus utilisée. Alors j'ai donc cherché SDK Blend for Silverlight 5 et je n'ai rien trouvé ? Rassurez-vous le Blend SDK for Silverlight 4 est compatible avec Silverlight 5. Ouf !


Expression Blend Installation

Je trouve que tous les outils Expression Studio de Microsoft sont difficiles à trouver, à installer, à utiliser ... JE trouve que Blend notamment est trop lié au développement d'application .NET. Bref ce n'est pas une partie de plaisir. La page la plus actuelle pour découvrir ces outils Ici.

Quelle ne fut pas ma stupeur après avoir téléchargé Blend Ici. Notez que je ne me suis pas enregistré la première fois, je n'avais pas envie de laisser mes coordonnées à un tas de commerciaux qui spammeront mon adresse email.

En cliquant sur Blend.fr.msi voici le résultat que j'ai obtenu :

Installation de Blend - Patienter pendant que le programme calcule l'espace disque nécessaire ...
Vous pouvez patienter indéfiniment il ne se passera rien ! Je suis donc retourné vers la page de téléchargement, je me suis enregistré et cette fois j'ai installé la version d'évaluation de Blend.

MVVM Pattern - Décisions clefs

Implementing the MVVM Pattern

http://msdn.microsoft.com/en-us/library/gg405484(v=pandp.40).aspx

Key Decisions

When you choose to use the MVVM pattern to construct your application, you will have to make certain design decisions that will be difficult to change later on. Generally, these decisions are application-wide and their consistent use throughout the application will improve developer and designer productivity. The following summarizes the most important decisions when implementing the MVVM pattern:
  • Decide on the approach to view and view model construction you will use. You need to decide if your application constructs the views or the view models first and whether to use a dependency injection container, such as Unity or MEF. You will usually want this to be consistent application-wide. For more information, see the section, "Construction and Wire-Up," in this chapter and the section "Advanced Construction and Wire-Up," in Chapter 6, "Advanced MVVM Scenarios."
  • Decide if you will expose commands from your view models as command methods or command objects. Command methods are simple to expose and can be invoked through behaviors in the view. Command objects can neatly encapsulate the command and enabled/disabled logic and can be invoked through behaviors or via the Command property on ButtonBase-derived controls. To make it easier on your developers and designers, it is a good idea to make this an application-wide choice. For more information, see the section, "Commands," in this chapter.
  • Decide how your view models and models will report errors to the view. Your models can either support IDataErrorInfo or, if using Silverlight, INotifyDataErrorInfo. Not all models may need to report error information, but for those that do, it is preferable to have a consistent approach for your developers. For more information, see the section, "Data Validation and Error Reporting," in this chapter.
  • Decide whether Microsoft Expression Blend design-time data support is important to your team. If you will use Expression Blend to design and maintain your UI and want to see design time data, make sure that your views and view models offer constructors that do not have parameters and that your views provide a design-time data context. Alternatively, consider using the design-time features provided by Microsoft Expression Blend using design-time attributes such as d:DataContext and d:DesignSource. For more information, see "Guidelines for Creating Designer Friendly Views" in Chapter 7, "Composing the User Interface."
Il faut impérativement se poser ces questions afin de trouver la bonne implémentation du Design Pattern MVVM en C#.NET.

HappyNet v1.2 - Exécution dans le navigateur Chrome

Au passage, curieux de savoir si mon exemplaire HappyNet, application Silverlight Hostée par une appli ASP.NET fonctionne, je copy colle l'url de mon application dans Chrome :

Et dans Chrome HappeNet fonctionne ?
Au miracle ça fonctionne ...

HappyNet v1.2 - Silverlight MVVM Prims

HappyNet v1.2 description

Superbe projet réalisé en Silverlight 5.0 sous Visual Studio 2010 avec une architecture MVVM utilisant Prism. Je peux le dire maintenant, c'est un véritable joyaux que je vais tenter de mettre en oeuvre sur ma machine et tenter de voir de quoi il retourne.

Requirements :
Au moment ou je tente d'explorer ce projet j'ai installé sur ma machine de dev :
Visual Studio 2010
Sivlerlight 5
Prims 4.1.0

Ce projet et ses sources se trouvent dans le Codeplex à l'adresse suivante :
http://happynet.codeplex.com/releases
http://happynet.codeplex.com/releases/view/96450

Démonstration en ligne :
http://silverlight.soat.fr/#Demonstrations

J'ai trouvé d'autre version de ce projet dans AllInOnSamples, trop ancienne Silverlight 3.0
Je suis donc assez content que l'auteur Cyril Cathala est réalisé un update de son magnifique projet.

Est-il facile à installer, à utiliser ?
On télécharge les sources dans une répertoire de travail et là au moment de cliquer sur la solution c'est la catastrophe !

Problèmes rencontrés dès le départ

Dans :
\\HappyNet v1.2 - SL5 ref\HappyNet-SL5\_Install
Le fichier :
Install.txt parle de procédures stockées dans un répertoire : _Documentation qui n'existe pas dans la release ! et pourtant dans ce répertoire on a bien deux procédures stockées. Ce n'est donc pas encore perdu.

Il existe deux ensemble de librairies Prism dans :
\\HappyNet v1.2 - SL5 ref\HappyNet-SL5\_Assemblies\Prism
Et dans :
\\HappyNet v1.2 - SL5 ref\HappyNet-SL5\packages\Prism.4.1.0.0\lib\SL5
Prims aurait été installé comme NuGetPackage

Directives Using

Les directives using utilisent : Prism.composite ...
using Microsoft.Practices.Composite.UnityExtensions;
using Microsoft.Practices.Composite.Modularity;
using Microsoft.Practices.Composite.Regions;
using Microsoft.Practices.Composite.Presentation.Regions;
using Microsoft.Practices.Composite.Events;

On va les remplacer dans tout le projet par :
using Microsoft.Practices.Prism.UnityExtensions;
using Microsoft.Practices.Prism.Modularity;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Prism.Events;

Les "XML Name Space" xmlns: dans les fichiers .xaml

Je trouve que bien souvent c'est le plus dur et que malgré l'intellisence modifier les names spaces dans les fichiers xaml c'est toujours délicat.

Donc voici ce que j'ai fais :
Dans \\HappyNet v1.2 - SL5\HappyNet-SL5\ButtonStyles.xaml
Je remplace :
xmlns:Regions="clr-namespace:Microsoft.Practices.Composite.Presentation.Regions;assembly=Microsoft.Practices.Composite.Presentation"
xmlns:cal="clr-namespace:Microsoft.Practices.Composite.Presentation.Commands;assembly=Microsoft.Practices.Composite.Presentation"
Par :
xmlns:Regions="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism"
xmlns:cal="clr-namespace:Microsoft.Practices.Prism.Commands;assembly=Microsoft.Practices.Prism"

Certains projets utilisent encore Silverlight 4.0

Dans le fichier :
\\HappyNet v1.2 - SL5 ref\HappyNet-SL5\Client\Core\Soat.HappyNet.Silverlight.DataContract\Soat.HappyNet.Silverlight.DataContract.csproj
On trouve :
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
Que l'on va remplacer par :
    <TargetFrameworkVersion>v5.0</TargetFrameworkVersion>

Lancer l'exécution du projet HappyNet v1.2

On arrive maintenant à compiler, on se dit que cela y est et on lance une exécution et bien sûr c'est la catastrophe ! Il reste deux ou trois petite chose avant de lancer une exécution ...

Configuration du serveur IIS

Il me semble que j'ai créé un répertoire virtuel ... ?
Propriétés du projet \\HappyNet v1.2 - SL5\HappyNet-SL5\Web\Soat.HappyNet.WebSite\Soat.HappyNet.WebSite
Il me semble bien avoir cliqué sur le bouton "Create Virtual Directory" ...

L'application Web qui Host le Silverlight ne charge pas le .xap

Encore une autre erreur : le site Web c'est à dire l'application web qui host le silverlight :
\\HappyNet v1.2 - SL5\HappyNet-SL5\Web\Soat.HappyNet.WebSite\ClientBinSoat.HappyNet.Silverlight.xap
N'est pas foutue de charger le .xap ...
Solution :
Démarrer->Tous les programmes->Outils d'administration->Gestionnaire des services Internet (IIS) :
Répertoire vituel host de l'application Silverlight : HappyNet
Bouton droit->Propiétés->Onglet : Sécurité des répertoires->Authentification et contrôle d'accès->Bouton Modifier :
Cochez la case Authentification Windows intégrée ...
Pensez à cocher la case ...

Soat.HappyNet.Silverlight.xap se charge dans l'internet explorer

Encore une erreur d'un autre monde cette à l'exécution de l'application Silverlight :

CommunicationException publier un fichier de stratégie
J'adore cette erreur de 14 km où l'on y parle de stratégie inadaptée aux services SOAP. Où il faudrait contacter le propriétaire du service pour autorise l'envoi d'en-tête HTTP-SOAP.

De quoi s'agit-il ? Avec Silverlight on aura pris l'habitude de découvrir le fameux fichier :
C:\Inetpub\wwwroot\clientaccesspolicy.xml

Et son contenu :

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="SOAPAction">
<domain uri="*" />
</allow-from>
<grant-to>
 <resource path="/" include-subpaths="true" />
</grant-to>
</policy>
</cross-domain-access>
</access-policy>

Sans quoi rien ne fonctionne ...

Enfin la fenêtre principale de l'application apparaît

file:///E:/HappyNet%20v1.2%20-%20SL5/HappyNet-SL5/Client/Core/Soat.HappyNet.Silverlight/Bin/Debug/TestPage.html#home

Exécution en mode debug  de l'application Silverlight Hostée par une appilcation Web : HappyNet v1.2
Pour rire je clique sur l'onglet Boutique :

HappyNet v1.2 onglet Boutique
Au bout d'un certain temps ... :


Détail de cette Exception Générale :


Et oui ! Je n'ai pas encore installé la SQL Server DataBase AdventureWorks for SQL Server 2008 que l'on peut d'ailleurs trouver ici :

http://msftdbprodsamples.codeplex.com/releases/view/37109

Tout n'est pas encore gagné ...

Conclusion 

Trouvez-vous que Silverlight for Web c'est vraiment Happy ?

Maintenant que je suis rassuré par l'exécution de ce projet, je souhaite le découvrir plus avant le code source mais certaines choses m'étonnent ...

Et je le crois, m'étonneront toujours. Notamment tout le code source présent dans le projet Soat.HappyNet.Silverlight :
Par exemple :
\\HappyNet v1.2 - SL5\HappyNet-SL5\Client\Core\Soat.HappyNet.Silverlight.Library\Commands\DelegateCommand.cs

Ou bien dans :
E:\HappyNet v1.2 - SL5\HappyNet-SL5\Client\Core\Soat.HappyNet.Silverlight.Library\Behaviors\DataStateBehavior.cs

Avec son entête :
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Permissive License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.
// http://expressionblend.codeplex.com/

Mais son name space :
namespace Soat.HappyNet.Silverlight.Library.Behaviors

A t-on vraiment besoin de tout ce code pour faire fonctionner une simple application Silverlight ?

HappyNet v1.2 Silverlight with Prism Mais qu'est ce que c'est que tout ce code  ?
Pour aller plus loin jetez un oeil ici :
http://www.microsoft.com/en-us/sharedsource/default.aspx

Il semble bien que certaines choses et certains mystères de Silverlight soit réservés à ceux qui sont initiés ...

MVVM de Prism

Afin de poursuivre mon tour complet sur l'architecture des nouvelles applications modernes, je regarde vers Prism. J'ai le sentiment que Prism intègre le travail réalisé sur le modèles MVVM par les différentes communautés.

Et comme j'ai accès aux sources et bien je vais faire un tour rapide des sources.

Petit tour rapide dans le Framework MVVM Prims

On trouve la solution Visual Studio 2010 dans :
\\Prism\PrismLibrary\PrismLibrary_Desktop.sln

Les sources dans :
\\Prism\PrismLibrary\Desktop\Prism
Projet spécifique, type Class Libray :
\\Prism\PrismLibrary\Desktop\Prism\Prism.Desktop.csproj
Assembly name : Microsoft.Practices.Prism

Cet assembly est bien au coeur de prism et traite du modèle MVVM.

Commands

public abstract class DelegateCommandBase : ICommand, IActiveAware
public class DelegateCommand<T> : DelegateCommandBase

public DelegateCommand(Action<T> executeMethod)
            : this(executeMethod, (o)=>true)

public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
            : base((o) => executeMethod((T)o), (o) => canExecuteMethod((T)o))

Remarque : c'est bien quasiement les même que les RelayCommand de Laurent Bugnion

les RelayCommand dérivaient d'une surcharge d'Action les WeakAction
Les DelegateCommand utilisent plutôt un WeakEventHandlerManager sur le EventHandler CanExecuteChanged

/// The CompositeCommand composes one or more ICommands.
public partial class CompositeCommand : ICommand

Autres commands :
This Behavior is required in Silverlight, because Silverlight does not have Commanding support.
public class ButtonBaseClickCommandBehavior : CommandBehaviorBase<ButtonBase>
public static class Click

Events

Va t-on trouver les objets Prism qui nous permettrons de gérer la communication entre ViewModels ?
public class EventAggregator : IEventAggregator
{
   private readonly Dictionary<Type, EventBase> events = new Dictionary<Type, EventBase>();

public class BackgroundEventSubscription<TPayload> : EventSubscription<TPayload>
public class DispatcherEventSubscription<TPayload> : EventSubscription<TPayload>
public class CompositePresentationEvent<TPayload> : EventBase

Logging

public class TraceLogger : ILoggerFacade
public class TextLogger : ILoggerFacade, IDisposable

Modularity

J'ai l'impression qu'ici on est dans le socle de base des MefExtensions et UnityExtensions

Regions

public class ContentControlRegionAdapter : RegionAdapterBase<ContentControl>
public abstract class RegionAdapterBase<T> : IRegionAdapter where T : class

Regions\Beaviors

...

ViewModel

public abstract class NotificationObject : INotifyPropertyChanged
Certains projets ont leur propre BaseViewModel ou encore ViewModelBase ou encore hérite du NotificationObject ...

Autres objets du framework

public class ObservableObject<T> : FrameworkElement, INotifyPropertyChanged
public abstract class Bootstrapper

Comparaison des sources de Silverlight et de Desktop

Par desktop on entend WPF bien évidemment.

\\Prism\PrismLibrary\Desktop (à gauche)
\\Prism\PrismLibrary\Silverlight (à droite)

Sources Prism Desktop - Sources Prism Silverlight (1)
Sources Prism Desktop - Sources Prism Silverlight (2)
Curieux non ? De constater à quel point il faut plus de code pour Desktop que pour Silverlight ...



MVVM de Josh Smith

L'implémentation du modèle MVVM qu'en a fait Josh Smith se trouve autrement appelé dans le codeplex : MVVM Foundation

http://bubbleburst.codeplex.com/
Un projet de jeux avec des balles ou des bulles que l'on fait disparaître lorsque l'on clique sur des bulles de la même couleur. Utilise la DLL :  MvvmFoundation.Wpf.dll
et une autre DLL : Thriple.dll

http://mvvmfoundation.codeplex.com/
Le framework MVVM écris par Josh Smith

http://joshsmithonwpf.wordpress.com/2009/07/11/one-way-to-avoid-messy-propertychanged-event-handling/
Forum, discussion sur la façon de traiter proprement les événements PropertyChanged

Principes du MVVM de Josh Smith

Le modèle MVVM de Josh Smith repose sur la création de quatre classes :

ObservableObject : classe de base des ViewModel ou de tous types qui doit fournir des notifications de PropertyChange, implémente l'interface INotifyPropertyChanged. Cette classe peut se nommer à l'usage ViewModelBase.
protected void RaisePropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName); // Debug purpose

PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}

RelayCommand : Dérive de l'interface ICommand et permet d'implémenter les Commands
public class RelayCommand : ICommand
{
readonly Action _execute;
readonly Func<bool> _canExecute;

public RelayCommand(Action execute) : this(execute, null)
{
}

public RelayCommand(Action execute, Func<bool> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");

_execute = execute;
_canExecute = canExecute;
}

public void Execute(object parameter)
{
_execute();
}
}

public class RelayCommand<T> : ICommand
{
        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }
       ...
}

PropertyObserver : Une méthode standard pour gérer l'événement INotifyPropertyChanged.PropertyChanged des autres objets. Cette classe utilise des références faibles (weak references) et le pattern weak-event pour éviter les fuites de mémoire !
public class PropertyObserver<TPropertySource> : IWeakEventListener where TPropertySource : INotifyPropertyChanged
{
public PropertyObserver(TPropertySource propertySource)
{
if (propertySource == null)
throw new ArgumentNullException("propertySource");

_propertySourceRef = new WeakReference(propertySource);
_propertyNameToHandlerMap = new Dictionary<string, Action<TPropertySource>>();
}
       ...
}

Messenger : Mécanisme léger de passage de messages entre les différents ViewModel basé sur l'implémentation du pattern Mediator.
public class Messenger
{
public void Register(string message, Action callback)
{
this.Register(message, callback, null);
}

public void Register<T>(string message, Action<T> callback)
{
this.Register(message, callback, typeof(T));
}

void Register(string message, Delegate callback, Type parameterType)
{
if (String.IsNullOrEmpty(message))
throw new ArgumentException("'message' cannot be null or empty.");

if (callback == null)
throw new ArgumentNullException("callback");

this.VerifyParameterType(message, parameterType);

_messageToActionsMap.AddAction(message, callback.Target, callback.Method, parameterType);
}

public void NotifyColleagues(string message, object parameter)
{
if (String.IsNullOrEmpty(message))
throw new ArgumentException("'message' cannot be null or empty.");

Type registeredParameterType;
if (_messageToActionsMap.TryGetParameterType(message, out registeredParameterType))
{
if (registeredParameterType == null)
throw new TargetParameterCountException(string.Format("Cannot pass a parameter with message '{0}'. Registered action(s) expect no parameter.", message));
}

var actions = _messageToActionsMap.GetActions(message);
if (actions != null)
actions.ForEach(action => action.DynamicInvoke(parameter));
}

...
}

Utilisation de MVVM Foundation

TBC (To Be Continued)