2010-06-27 3 views
3

J'ai une idée, mais j'ai besoin d'aide pour l'implémenter.Sérialisation de délégués dans WCF à l'aide d'un substitut?

WCF ne prend pas en charge les délégués dans ses contrats. Au lieu de cela, il a un lourd mécanisme de contrats de rappel, et je cherche un moyen de surmonter cette limitation.

J'ai pensé à utiliser un IDataContractSurrogate pour remplacer chaque délégué du contrat par un jeton qui sera sérialisé vers le point de terminaison distant. Là, le jeton sera désérialisé en un délégué généré. Ce délégué générera un message de rappel générique qui encapsule tous les arguments (avec lesquels le délégué a été appelé).

Le message de rappel générique atteindra le premier point de terminaison, et là le délégué d'origine sera invoqué avec les arguments.

Voici la séquence purposed (simplifiée):

  1. A appelle B-proxy.Foo (rappel)
  2. rappel est sérialisé par un DelegateSurrogate.
  3. Les DelegateSurrogate stocke le délégué dans un stockage délégué dédié et le remplace par un jeton
  4. Le message arrive au point final de B
  5. le jeton est désérialisée par un DelegateSurrogate
  6. Le DelegateSurrogate construit un délégué généré
  7. B.Foo (generatedCallback) est appelé
  8. Plus tard, B appelle generateCallback (args)
  9. generatedCallback (args) appelle un contrat générique dédié sur le point de terminaison A: Callback Contrat-proxy.GenericCallback (args)
  10. CallbackContract.GenericCallback (args) est invoquée sur le point final d'un
  11. Le rappel d'origine est récupéré à partir du stockage et est invoquée: rappel (args)

J'ai déjà mis en œuvre ce bus de service utilisant précédemment (NServiceBus), mais je veux adapter l'idée à WCF et j'ai du mal à le faire. Je sais comment mettre en œuvre les étapes 3,6,9 et 11. Je ne sais pas encore comment câbler tout dans WCF - en particulier la partie de substitution.

C'est tout - J'espère que ma question a du sens, et que la sagesse collective ici sera en mesure de m'aider à construire cela.

Voici un exemple d'utilisation pour ma solution désirée:

// client side 
remoteSvc.GetEmployeeById(17, emp => 
{ 
    employees.Add(emp); 
    logger.log("Result received"); 
}); 

// server side 
public void GetEmployeeById(int id, Action<Employee> callback) 
{ 
    var emp = getEmpFromDb(id); 
    callback(emp); 
} 
+0

Pourquoi le mécanisme de rappel standard est-il «encombrant»? –

+0

parce que vous avez besoin d'un code standard pour l'utiliser, et vous aurez besoin d'apprendre ce mécanisme. Aussi - Je ne crois pas que cela fonctionnera dans des canaux à sens unique comme MSMQ. Les délégués en tant que rappels sont plus intuitifs car ils ressemblent à du code C# régulier. –

Répondre

2

En fait, dans ce scénario, je regarderais dans l'API Expression. Contrairement à un délégué, un Expression peut être déconstruit lors de l'exécution. Vous ne pouvez pas les sérialiser par défaut, mais un lot of work a été fait dans cet espace. C'est aussi un peu comme ce que beaucoup de fournisseurs LINQ font en arrière-plan, par exemple les services de données WCF.

Bien sûr, une autre approche consiste simplement à utiliser une expression lambda comme crochet pour RPC, ce que je décris here.Le code qui l'implémente est disponible gratuitement dans l'arbre protobuf-net. Vous pouvez personnaliser cela en utilisant un attribut pour associer votre jeton à la méthode et obtenir l'attribut à partir du MethodInfo.

IMO, le problème avec délégués est qu'ils sont trop étroitement couplés à l'implémentation, donc vous ne pouvez pas avoir différentes implémentations à chaque extrémité (ce qui est une exigence commune).

expressions ont l'avantage lambdas encore le soutien IntelliSense etc, afin que vous puissiez faire des choses comme:

client.Invoke(svc => svc.Foo(123, "abc")); 

et de cette obtenir Foo (le MethodInfo), 123 et "abc" séparément, y compris les variables capturées, ref/out, etc. Tout fonctionne.

+0

wow, excellente réponse, je vais devoir regarder dans ces technologies – andy

+0

Merci pour la réponse, mais ce n'est pas ce que je cherchais. D'abord, les arbres d'expression ne sont pas une option pour un lambdas avec des corps d'instruction. Deuxièmement, je ne sais toujours pas comment écrire ma mère porteuse et la transmettre à la WCF. Je vais ajouter un exemple de cas d'utilisation à la publication principale pour essayer de le rendre plus clair. –

+0

@Omer - dans 4.0, 'Expression' prend en charge les corps d''instruction. Le compilateur C# * ne le supporte pas, mais 'Expression' * le fait *. Ça peut être fait. –