Utiliser l'approche Contract First avec Workflow Foundation 4.5

Article par Jérémy Jeanson (MVP Microsoft Integration)

Dn751566.441B1C6270D8C455855F77E77713EA9C(fr-fr,MSDN.10).png

Dn751566.7B654F178A3842F7F616A829DC6DF588(fr-fr,MSDN.10).png

Développant avec .net depuis 2001, j’ai vécu les différentes évolutions du Framework, des premières Beta de la version 1.0 à aujourd’hui. Je surfe donc sur la vague .net depuis ses débuts, et j’adore cela.


À force de pratiques et d’expériences personnelles, je me suis spécialisé dans les architectures n-tiers exploitant Windows Communication Foundation, Windows Workflow Foundation et plus généralement l’interopérabilité des services. Mais il m'arrive de travailler sur tous types de matériels, du serveur au smartphone tout en passant par la tablette.

Mai, 2014


Prérequis

Depuis l’arrivée de .net 4.5, les services Workflow Foundation sont en mesure de respecter un contrat WCF préétabli. Pour en profiter, il faut donc avoir :

  • .net 4.5
  • Visual Studio 2012 ou 2013

L’approche Contract First peut être reproduite sur tout type de projet .net 4.5


Implémentation

Afin de faciliter la compréhension de l’implémentation d’un contrat sur un service de workflow, j’ai créé une solution contenant deux projets. Le premier comprend mes contrats et le second mes services.

Le projet contenant les services est de type «WCF Workflow Service Application ». Ceci facilite les manipulations, car il rend accessible la commande « Import Service Contract ». La manipulation permettant de disposer de commande sur tout type de projet est décrite un peu plus loin dans cet article.

Dn751566.FFA7A68BFB8B7E888A7EDF4D35DA3651(fr-fr,MSDN.10).png

A ce stade, ma solution ressemble à ceci :

Dn751566.C46C06F851F8FCD3BB650F277DFD81B7(fr-fr,MSDN.10).png

Dans le projet des contrats, j’ai créé le contrat suivant

using System;
using System.Runtime.Serialization;
using System.ServiceModel;

namespace Contracts
{
    [ServiceContract(Namespace="http://mycompany.com/commercialrequests")]
    public interface ICommercialRequestProcess
    {
        [OperationContract]
        Guid RequestDocumentations(Guid userId, Documentation[] documentations);

        [OperationContract]
        Boolean Accept(Guid userId);

        [OperationContract]
        Boolean Reject(Guid userId);
    }

    [DataContract(Namespace = "http://mycompany.com/data/documentation")]
    public class Documentation
    {
        [DataMember]
        public Guid Id { get; set; }

        [DataMember]
        public String Title { get; set; }
    }
}
Dn751566.note(fr-fr,MSDN.10).gifNote:
Le DataContract n’est pas obligatoire, il est là pour prouver jusqu’où on peut aller dans l’utilisation d’un contrat WCF


Après compilation du projet contenant les contrats, on peut ajouter celui-ci comme référence au second projet (celui des services). Afin que WF prenne en compte les contacts, il est utile de demander d’importer de ceux-ci. Pour réaliser cette manipulation, il suffit de faire un clic droit sur le projet des services et d’utiliser la commande « Import Service Contracts ». Cette commande permet d’ouvrir une boite de dialogue nous demandant quel contrat doit être importé :

Dn751566.8E08893004F5C00257CECF2C846BA972(fr-fr,MSDN.10).png

Après validation du choix du contrat, une seconde boite de dialogue s’ouvre. Celle-ci nous indique que des activités ont été générées et qu’il faut compiler notre projet pour en profiter.

Dn751566.EC5BDCC09199F30BF78B1AC11B698D20(fr-fr,MSDN.10).png

Le projet a maintenant un nouveau dossier « Service Contracts », ainsi qu’un lien représentant notre contrat.

Dn751566.09184DB308BA54AA4A5FA1EC5E1359AD(fr-fr,MSDN.10).png

Côté service, il reste maintenant à indiquer au workflow qu’il doit respecter le contrat. Pour ceci, il faut ouvrir le workflow (fichier .xamlx) et afficher ses propriétés. On peut alors éditer sa collection de contrats.

Dn751566.note(fr-fr,MSDN.10).gifNote:
Un service de workflow peut avoir plusieurs contrats WCF.

Dn751566.6AB0433F54427FFB6F83637728D8F432(fr-fr,MSDN.10).png

La fenêtre qui s’ouvre affiche les contrats déjà implémentés (dans notre cas, il n’y en a pas). Pour ajouter le contrat, il faut donc utiliser la commande « Add new type »

Dn751566.405558DB5CE7B784B7F6068849E23E68(fr-fr,MSDN.10).png

A l’ouverture du menu déroulant, on doit choisir « Browse for Types … » 

Dn751566.E2F215DD613A6F0CF56F4C344BD84B18(fr-fr,MSDN.10).png

On peut alors sélectionner le contrat

Dn751566.40A716460B445953D0EA8E4EADA67A0A(fr-fr,MSDN.10).png

Après validation de cette dernière boite de dialogue, Visual Studio nous signifie que le service ne respecte pas le contrat (normal! nous n’avons pas encore utilisé les activités générées précédemment)

Dn751566.EF9461401ED09638390DD3976860D4B7(fr-fr,MSDN.10).png

J’ai replacé les activités de mon service par défaut par une « Sequence ». On peut constater que celle-ci aussi nous indique le non-respect du contrat.

Dn751566.E27C4EA798F816011AA91DAB3D41DF6C(fr-fr,MSDN.10).png

Il nous reste donc maintenant à utiliser les activités de notre contrat. On trouvera celles-ci dans la toolbox du designer de workflow.

Dn751566.41DB47D778B6379C7399A21068108C0F(fr-fr,MSDN.10).png

Dn751566.note(fr-fr,MSDN.10).gifNote:
Pour chaque contrat importé, on aura un groupe d’activités. Ces activités seront systématiquement regroupées par non de contrat.

Une fois l’ensemble des activités utilisées, les messages d’avertissement disparaissent. Bien entendu, il faut aussi penser à gérer la corrélation et à définir l’activité qui a le droit d’instancier des workflows.

Dn751566.BEA4E81BE6144E5AFFD9ED7A073C961D(fr-fr,MSDN.10).png

Pour vérifier le fonctionnement de notre service, on peut lancer l’outil de test WCF livré avec Visual Studio.

Dn751566.5D97734230DE960AB9885B56199762B5(fr-fr,MSDN.10).png

Tout est bon. Si on a la curiosité de regarder du côté de la vue XML, on constatera que les namespaces sont respectés (tant sur le ServiceContract que sur les DataContract).

Notre service respecte donc bien le contrat WCF dans sa totalité. Si on le souhaite, on peut changer le fichier de configuration comme pour tout autre service WCF. Cela ne posera pas le moindre problème.


Mettre à jour un contrat

Si le contrat venait à changer. Après compilation de l’assembly le contenant, il suffit de faire un clic droit sur le contrat importé, commande «Update Service Contract ».

Dn751566.F48F5EE7894FA32D57271FA50D2A1965(fr-fr,MSDN.10).png

Ensuite, il faut procéder à une compilation du projet contenant le service. Pour finir, il faut mettre à jour le service en y ajoutant / supprimant les éléments du contrat mis à jour.


Limites de l’approche Contract First et des mises à jour du contrat

Les définitions Xaml de service ne prenant pas en charge le refactoring, il existe quelques limites qu’il faut prendre en compte lors de l’évolution ou la mise à jour du contrat. Les cas suivants ne pourront être pris en compte sans une modification manuelle du contenu du fichier Xamlx.

  1. Renommer un contrat (nom de l’interface)
  2. Renommer une méthode du contrat
  3. Ajouter/supprimer des arguments à une méthode
  4. Changer le type d’un argument ou d’un retour de méthode
  5. Renommer le namespace d’un DataContract ou du ServiceContract

Dans ces situations, il est préférable de noter chaque changement et d’utiliser l’éditeur XML de Visual Studio pour modifier à la main le XAML (utiliser la touche F7 de votre clavier, quand le fichier Xamlx est sélectionné)

Disposer de la commande « Import Service Contract » sur tout type de projet

Si le projet contenant vos services n’est pas de type « WCF Workflow Service Application », la commande « Import Service Contract » n’est pas disponible. Pour la rendre accessible, il faut modifier le fichier .prj de son projet.

Pour commencer, on sélectionne le projet. On utilise son menu contextuel pour le décharger (clic droit, « Unload project »)

On peut alors éditer le fichier .prj

Dn751566.B35CEE775CBAD9069A76B0FB0455A529(fr-fr,MSDN.10).png

On y ajoute le Guid {32f31d43-81cc-4c15-9de6-3fc5453562b6} dans le nœud <ProjectTypeGuids>

Dn751566.4BAC18F6D90A3F0327925F62F0ED0943(fr-fr,MSDN.10).png

Pour finir, on recharge.

Dn751566.2F4EDFA2C79695A73CB5690AA6EEFA68(fr-fr,MSDN.10).png

La commande « Import Service Contract » est alors disponible via le menu contextuel du projet.

Dn751566.AA0D1D791032C89E5D2A81CA136B3C79(fr-fr,MSDN.10).png


Avoir plusieurs SendReply pour une même activité Receive

Pour une même activité Receive, on peut avoir besoin d’associer plusieurs activités SendReply. Par exemple, dans le cas d’une activité « If », on peut souhaiter envoyer une réponse dans une branche « Then » et une autre dans le « Else ». Ceci est rendu possible via la commande « Create SendReply ».

Dn751566.C759F3032E2EC2B54A05E4423D7AB077(fr-fr,MSDN.10).png

Dans le cas où un contrat doit être implémenté, on se retrouve conforté à une erreur, conformément à la capture suivante :

Dn751566.A92AABE9A5C8E535BABADA141055CCB7(fr-fr,MSDN.10).png

Bien entendu, on pourrait contourner le problème en n’utilisant qu’un seul « SendReply » et en le plaçant après le « If ».

Dans la situation où il nous faut impérativement deux « SendReply », il faut comparer les propriétés et le contenu de chaque activité « SendReply ».

Activité créée par le Template Code First

Activité créée via la commande « Create SendReply »

Dn751566.A784905D16E7575359A226A637346118(fr-fr,MSDN.10).png

Dn751566.9830F139758AC6A8662B2B809BBD2659(fr-fr,MSDN.10).png


Activité créée par le Template Code First

Activité créée via la commande « Create SendReply »

Dn751566.5FAF38F1A018BEAD35F8D54B1C9C2A3D(fr-fr,MSDN.10).png

Dn751566.053FE7EB758F0BEA07DDA7B5FBF75F1F(fr-fr,MSDN.10).png


On constate que :

  • La propriété « Action » n'est pas bonne.
  • Les paramètres du message ne sont pas bons.

Si on corrige ses deux éléments, le service respecte à nouveau le contrat. On peut donc avoir plusieurs « SendReply » pour un même « Receive », ceci impose juste un peu plus de manipulations.

Afficher: