2008-12-04 10 views
2

Je travaille sur une application qui utilise WCF pour communiquer entre le serveur et les clients Le serveur a un nombre de services changeant, ainsi qu'un service maître que les clients peuvent interroger pour obtenir des informations sur d'autres services, puis abonnez-vous à ceux qu'ils veulent en utilisant les informations du service principal.Comment: répondre à la communication bidirectionnelle Wcf disponible

Le service principal envoie des notifications aux clients abonnés, lorsque les sous-services changent (ajouté, supprimé, etc.) Les sous-services envoient également des notifications toutes les quelques secondes. Cela ressemble à une excellente occasion d'utiliser les canaux de rappel WCF, mais ils nécessitent que vous utilisiez la session. Aussi lors de l'envoi de notifications aux clients, lorsque l'un des cliens se déconnecté disgracieusement le service se bloque, en essayant de le notifier. Même si cela expire, après un certain temps, aucun autre client n'est averti pendant cette période et ce n'est pas acceptable, car les clients sont en fait des interfaces graphiques pour la surveillance des applications derrière les sous-services. Utiliser également MSMQ pour cela n'est pas une option, puisque le service doit savoir immédiatement, lorsque l'opération d'envoi n'a pas réussi. La solution que j'ai trouvée est d'utiliser la liaison http (savoir immédiatement quand l'envoi n'a pas réussi) et de créer des services de rappel explicites sur le client, mais cela m'oblige à écrire beaucoup de code d'infrastructure laid. Donc, ma question est la suivante: y a-t-il une meilleure façon de le faire avec WCF? La meilleure option était Callback Contracts, parce que cela me libère de devoir gérer le service de rappel manuellement, si seulement il ne pouvait pas attendre ack d'un client avant d'essayer d'envoyer au suivant.

Répondre

3

J'ai un environnement similaire (sans les services dynamiques) et j'ai eu un problème très similaire lorsque les canaux clients étaient en défaut. La première solution que j'ai trouvée consistait à encapsuler les rappels dans les instructions try/catch et à supprimer le client fautif si quelque chose se passait mal mais cela avait des problèmes et ne semblait pas du tout redimensionner.

La solution que j'ai utilisée était d'utiliser un gestionnaire d'événements délégué et de l'appeler en utilisant BeginInvoke. Si vous n'avez pas examiné la solution CodeProject: WCF/WPF Chat Application (Chatters), je vous recommande de la vérifier.

Lorsqu'un utilisateur se connecte, un gestionnaire d'événements est créé et ajouté à l'événement principal:

public bool Login() 
{ 
    ... 
    _myEventHandler = new ChatEventHandler(MyEventHandler); 
    ChatEvent += _myEventHandler; 
    ... 
} 

Chaque fois qu'un message doit être diffusé, les gestionnaires d'événements sont appelés de manière asynchrone:

private void BroadcastMessage(ChatEventArgs e) 
{ 
    ChatEventHandler temp = ChatEvent; 
    if (temp != null) 
    { 
     foreach (ChatEventHandler handler in temp.GetInvocationList()) 
     { 
      handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null); 
     } 
    } 
} 

Lorsque les retours reviennent, le résultat est géré et si quelque chose de mal se produit, le gestionnaire d'événements de ce canal est supprimé:

private void EndAsync(IAsyncResult ar) 
{ 
    ChatEventHandler d = null; 
    try 
    { 
     //get the standard System.Runtime.Remoting.Messaging.AsyncResult,and then 
     //cast it to the correct delegate type, and do an end invoke 
     System.Runtime.Remoting.Messaging.AsyncResult asres = (System.Runtime.Remoting.Messaging.AsyncResult)ar; 
     d = ((ChatEventHandler)asres.AsyncDelegate); 
     d.EndInvoke(ar); 
    } 
    catch(Exception ex) 
    { 
     ChatEvent -= d; 
    } 
} 

Le code ci-dessus est modifié (légèrement) à partir de l'application de conversation WCF/WPF publiée par Sacha Barber.