2009-09-04 10 views
0

Aujourd'hui, j'ai une question WCF, même si elle concerne probablement d'autres modèles de mise en réseau dans .NET.WCF: DuplexSessionChannel, opérations asynchrones et une exception

J'ai un service WCF qui expose un OperationContract Send (Message), qui est OneWay = true. Maintenant, ce service a un canal de rappel pour renvoyer des messages au client.

Quoi qu'il en soit, j'essaie (avec succès) d'appeler cette méthode Send de mon client de manière asynchrone. Sur un DuplexSessionChannel j'appelle BeginSend (Message, OnSendComplete, null) et j'ai une méthode OnSendComplete (IAsyncResult) qui appelle EndSend (asyncResult) sur le DuplexSessionChannel.

Le service a un CallbackContract et utilise le même modèle BeginSend()/EndSend() pour renvoyer au client, qui est appelé sur le canal callBack que j'obtiens avec OperationContext.Current.GetCallbackChannel.

Le client sur son DuplexSessionChannel appelle BeginReceive()/EndReceive() lors de la réception de messages à partir du canal de rappel Services.

Même si les choses fonctionnent, je ne comprends pas ce que font réellement les méthodes End <Operation>() et c'est ce que j'ai besoin de m'expliquer. Je demande parce que je reçois une exception occasionnelle dans un appel à EndSend() sur le Service (renvoi au client) se plaindre qu'une collection a été modifiée (je sais ce que cette exception signifie, mais pas pourquoi il est passe ou où exactement ...). J'utilise PollingDuplexHttpBinding avec un client Silverlight. Je ne suis pas un expert WCF, mais ne vous retenez pas sur les détails, j'ai besoin de la connaissance. J'ai vu ce genre de modèles de début/fin avant d'autres opérations asynchrones au cours de ma carrière jusqu'à présent, mais je n'ai jamais vraiment compris ce qui se passait.

Merci d'avance.

Répondre

1

Il semble que votre question concerne uniquement le APM Begin/End (modèle de programmation asynchrone). En bref, l'APM prend une méthode de synchronisation comme

R Foo(A a); // R is some result type, A is some argument type 

et il se brise en méthodes et async BeginFoo EndFoo. Le principal avantage se produit lorsque l'opération effectue un fonctionnement du système véritablement asynchrone (par exemple en parlant au réseau) qui peut être long (au moins par rapport à d'autres fonctions, par exemple parler au réseau peut prendre des centaines de millisecondes ou plus). Ce modèle vous permet de dire au système de démarrer l'opération, puis de vous rappeler lorsque le résultat de l'opération est prêt. L'avantage du pattern est que vous n'avez pas besoin d'avoir un thread géré bloqué pendant que cet appel est en attente (ce qui signifie par exemple que vous pouvez avoir des milliers de lectures/écritures réseau en attente sans avoir besoin de milliers de threads). Donc, étant donné que 'BeginFoo' est ce que vous dites 'démarrer la méthode avec ces arguments', et quand vous êtes rappelé (comme notification que le résultat est prêt), 'EndFoo' est comment vous obtenez le résultat . Dans le cas général, si 'Foo' peut lancer une exception particulière, cette exception peut provenir de l'appel 'Begin' ou de l'appel 'End' et vous devez être prêt à le gérer aux deux endroits.

Dans le cas de quelque chose comme Send() (qui peut-être retourne vide, j'oublie), c'est un peu ennuyeux/bizarre parce que c'est à sens unique, vous voulez juste "fire-and-forget". Mais des exceptions peuvent encore se produire (par exemple, j'ai essayé d'envoyer mais quelqu'un a débranché mon câble réseau), et cela peut donner des exceptions ... et étant donné le APM Début/Fin, une telle exception pourrait sortir de l'appel EndSend.En effet, l'exception est une sorte de 'résultat' d'appel Send, et donc vous appelez EndSend fournit un moyen pour le système de lancer une exception pour vous dire que quelque chose s'est mal passé après avoir appelé BeginSend.

+0

Dans la WCF IDuplexSessionChannel.BeginSend et EndSend a la signature suivante: IAsyncResult BeginSend (message, AsyncCallback, objet) EndSend void (IAsyncResult); J'appelle EndSend depuis la méthode de rappel appelée par le délégué AsyncCallback transmis à BeginSend. Étant donné que EndSend() renvoie void, je ne comprends toujours pas à quoi cela sert. Le "résultat" que je vois provient de BeginSends AsyncCallback. Je ne comprends pas non plus pourquoi BeginSend retourne IAsyncResult, quand il est également retourné de manière asynchrone par le BeginSend AsyncCallback. – MrLane

+0

Lecture Brians poster encore quelques mois après que j'ai posté cette question les choses sont beaucoup plus claires avec ce modèle. Le livre de programmation WCF par Juval Lowery explique aussi bien cela. Je ne sais toujours pas la cause de l'exception, mais il a été éliminé car je n'appelle plus EndSend(), car je réalise qu'il n'y a aucun résultat renvoyé de toute façon. Je ne sais pas si c'est une bonne pratique (peut-être que je pourrais manquer des détails d'exception), mais le livre semble suggérer qu'il peut être omis, et puisque le retrait a été bien meilleur. – MrLane

Questions connexes