[WF4+WCF] Hoster un service WF sans Xamlx, ni IIS… ni BasicHttpBinding

Publié le 23 août 2010 par Jeremy.jeanson

Dans un environnement WF4 réel, il arrive que l'on ait à se passer d'IIS. Soit vous n'avez pas été sage avec votre administrateur préféré soit votre système hôte ne permet pas d'installer IIS. Dans tous les cas, vous avez besoin d'exposer un service de workflow via WCF. Comme de votre côté vous n'aimez pas les fichiers de configuration (ou que vous voulez vous venger de votre administrateur).

Pas de IIS pour le développeur L !!! ok et bien alors pas de fichier de configuration pour l'administrateur ;)

Il faudra donc charger la configuration à la main... et la metadata . Et pour corser le tout vous n'avez pas le droit à votre sempiternel BasicHttpBinding (qui personnellement me sort des yeux !) car le client de votre application est en local... Et que vous n'avez plus d'excuse valable pour expliquer à votre administrateur pourquoi vous déclencher l'UAC ou le firewall.

Qui dans la salle a dit désactive l'UAC et le firewall ?

Véridique il y a des développeurs qui font cela et que sortent un florilège d'explications bidons sur le sujet... bref je m'égard... je ne voudrais pas donner trop de matière à maîtresse Isabelle ;)

Enfin bref, vous êtes dans une situation courante : héberger un workflow exposé via les canaux nommés (NetNamedPipeBinding) dans une application ou un service windows. Mais vu que vous êtes sur du WF vous ne pouvez pas vous fier à un contrat de service, il faut donc aussi mettre à disposition la metadata du service pour générer le proxy de votre client via Visual Studio.

Si vous vous êtes renseigné vous avez peut-être une paire de soucis :

  • Le type MexNetNamedPipeBinding n'existe pas, donc l'exposition de la metadata du service ne serra pas possible.
  • Les workflow exposés doivent être de type Xamlx. Dommage si vous aviez prévu de passer par un designer de workflows custom hors de Visual Studio.
  • Les workflow Xamlx ne peuvent pas être instanciés comme des objets. Il faut passer par un reader xaml pour charger un fichier Xamlx... dnc pas de comilation L
  • ... etc ...

STOP ! Tout ceci est faut . Ce ne sont que des suppositions basées sur le fait que vous n'avez pas trouver d'autres solutions sur la toile... Bref encore une histoire de saucisses.

Pile poil le cas de psychopathe dont je voulais faire la démonstration ;)

Pour illustrer mes propos, je suis parti sur un nième workflow HelloWorld tel que celui-ci :

Ce workflow (xaml et non pas xamlX) expose une méthode expose une méthode Hello(name) qui retournera au client une string contenant le message : Hello + name + !

Et le code qui permet d'héberger ce service est le suivant (simple à condition d'aimer WCF et WF):

using System;
using System.Linq;
using System.Activities;
using System.Activities.Statements;
using System.ServiceModel.Activities;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace Demo.WF4.Server
{

    class Program
    {
        static void Main(string[] args)
        {
            // Nom de mon contrat de service (juste pour les yeux)
            String contractName = "IService";

            // Addresse du service
            Uri uri = new Uri("net.pipe://localhost/Server");

            // Création de l'hôte
            WorkflowServiceHost host = new WorkflowServiceHost(
                new WorkflowService()
                {
                    // Le Workflow exsposé via le service
                    Body = new WorkflowServer(),
                    // Endpoints du workflows
                    Endpoints = 
                    {
                        new Endpoint()
                        { 
                            ServiceContractName = contractName,
                            Binding = new NetNamedPipeBinding(),
                            AddressUri = uri
                        }
                    }
                }, 
                uri);

            // Ajout d'un behavior pour la mise à disposition des metadata via WCF
            host.Description.Behaviors.Add(new ServiceMetadataBehavior());

            // Ajout du endpoint servant aux metadatas
            host.AddServiceEndpoint(
                ServiceMetadataBehavior.MexContractName, 
                MetadataExchangeBindings.CreateMexNamedPipeBinding(),
                "mex");
            
            // Passage de l'hôte de service en écoute
            host.Open();

            // Le service est en ligne
            Console.WriteLine("Service en ligne");
            Console.Read();
        }
    }
}

Si je lance l'application, tout ce passe bien

Et si je prends un autre projet et que je tente d'y ajouter une référence à mon service. Visual Studio découvre bien mon service.

Promis un peu plus tard je parlerai des possibilités de WF pour consommer des services (encore une histoire de saucisses en perspective)