Frédéric Colin
WCF : L’extensibilité par la pratique – L’exemple
Dans le précédent volet, je vous ai expliqué une partie des fondamentaux de l’extensibilité WCF. Je vous ai aussi décrit le fonctionnel d’un exemple plus complet que je vais maintenant concevoir et développer pour illustrer l’invocation d’opération.
Par Frédéric Colin publié le 13/09/2009 à 22:18, lu 1083 fois, 9 pages
 4 | Implémentation de l’extensibilité personnalisée
L’extensibilité personnalisée mise en œuvre suit le schéma défini dans l’article précédent, à savoir la création des classes suivantes. L’une pour l’injection du comportement :
 
/content/9e0f12af-1850-46bd-aef3-086b984f980c/image9.png
 
La seule chose importante dans cette classe est finalement le remplacement du comportement d’invocation de base par le notre, en prenant soin de passer les paramètres permettant de récupérer l’invoker de base et aussi des informations sur l’opération demandée (structure du message, action, etc.).

public void ApplyDispatchBehavior(OperationDescription operationDescription,

    System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)

{

    // Override default Behavior

    dispatchOperation.Invoker = new FacadeOperationInvoker(

                                        dispatchOperation.Invoker,

                                        operationDescription);   

}

L’autre pour l’invocation d’opération :
 
/content/9e0f12af-1850-46bd-aef3-086b984f980c/image10.png
 
Sachant que je n’ai pas géré les appels asynchrones, le gros de travail est situé dans la méthode « Invoke », dont voici le code :

public object Invoke(object instance, object[] inputs, out object[] outputs)

{

    // Action Scheme is the following :

    // Assembly/ClassName/MethodName/MethodNameOverloadedIfNecessaryElseSameName

    String[] scheme = operationDescription.Messages[0].Action.Split("/".ToCharArray());

    Object returnValue = null;

 

    if (scheme.Length != 4)

        throw new ApplicationException("Error in method execution according this action : "

            + operationDescription.Messages[0].Action);

 

    // First Step : the assembly

    Assembly assemb = Assembly.LoadFrom(

        String.Format("{0}\\{1}.dll",

        ConfigurationManager.AppSettings["DirectoryToMonitor"],

        scheme[0])

        );

 

    if (null != assemb)

    {

        // Second Step : the type

        Type t = assemb.GetType(scheme[1]);

 

        if (null != t)

        {

            // Third step : create the instance

            Object obj = Activator.CreateInstance(t);

 

            // Fourth step : execute the method

            returnValue = obj.GetType().InvokeMember(scheme[2], BindingFlags.InvokeMethod, null, obj, inputs);

 

            // Fifth step : Manage output values. In fact, output values are not managed in this sample!

            outputs = new Object[0];

        }

        else

        {

            throw new Exception(String.Format("Type {1} in Assembly {0} not found", scheme[0], scheme[1]));

        }

    }

    else

    {

        throw new Exception(String.Format("Assembly {0} not found", scheme[0]));

    }

 

    return returnValue;

}

La première partie du travail consiste à récupérer les informations de type « Action » (via le membre « operationDescription » passé au constructeur de cette classe) du message pour en déduire l’Assembly, la classe et la méthode à appeler. Il eut été peut-être plus élégant et plus performant d’utiliser une expression régulière qu’un simple « split », mais c’est une autre histoire …
Le reste du travail consiste simplement à jouer un peu avec la « Reflection » pour charger s’il le faut l’Assembly, récupérer le type, en créer une instance et appeler dynamiquement la méthode via « InvokeMember ». Vous noterez deux choses :
  • Que le chargement de l’Assembly se fait via un répertoire paramétré dans le fichier de configuration du processus porteur.
  • Que je n’ai pas géré les paramètres en Ref et en Output.
 
» Démarrer une discussion