2010-05-26 4 views
4

Je travaille sur un projet en ce moment et je suis un peu coincé. Je crée une application de serveur client, qui permet à un client de s'abonner au serveur pour recevoir des messages. Le problème que j'ai, c'est que lorsque le client s'abonne, je souhaite qu'il reçoive uniquement les mises à jour qui s'y rapportent. Le système transmet essentiellement les messages d'une base de données SQL Server que le serveur surveille. Lorsqu'un nouveau message est reçu, le serveur doit seulement transmettre le message aux clients auxquels il s'applique, en fonction de ce qui a été enregistré sur l'ordinateur client. J'ai regardé et trouvé des exemples de code qui s'inscrivent pour que les messages soient diffusés sur tous les clients qui se sont abonnés, mais pas sur ceux qui montrent comment identifier les clients individuels et si les messages s'appliquent à eux.WCF Publier/S'abonner et utiliser les rappels pour envoyer des données à des utilisateurs spécifiques

Si quelqu'un pouvait m'aider ou me diriger dans la bonne direction, ce serait apprécié.

modifier Pour être plus clair, je ne suis pas tellement se demander comment faire fonctionner callbacks et abonnement, mais comment faire fonctionner un service d'abonnement où lorsqu'un utilisateur est abonné, ils peuvent y fournir des ID utilisateur ainsi que les informations de rappel, ce qui peut ensuite être utilisé pour identifier les utilisateurs spécifiques, les messages doivent être envoyés.

Vous pouvez maintenant trouver certains de mon code ci-dessous:

namespace AnnouncementServiceLibrary 
{ 
    [ServiceContract(CallbackContract = typeof(IMessageCallback))] 
    public interface IMessageCheck 
    { 
     [OperationContract] 
     void MessageCheck(); 
    } 
} 

namespace AnnouncementServiceLibrary 
{ 
    public interface IMessageCallback 
    { 
     [OperationContract(IsOneWay = true)] 
     void OnNewMessage(Mess message); 
    } 
} 

Inscription/désinscrire:

private static readonly List<IMessageCallback> subscribers = new List<IMessageCallback>(); 

     public bool Subscribe() 
    { 
     try 
     { 

      IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>(); 

      //If they dont already exist in the subscribers list, adds them to it 
      if (!subscribers.Contains(callback)) 
       subscribers.Add(callback); 
      return true; 
     } 
     catch 
     { 
      //Otherwise if an error occurs returns false 
      return false; 
     } 
    } 


    /// <summary> 
    /// Unsubscribes the user from recieving new messages when they become avaliable 
    /// </summary> 
    /// <returns>Returns a bool that indicates whether the operation worked or not</returns> 
    public bool Unsubscribe() 
    { 
     try 
     { 

      IMessageCallback callback = OperationContext.Current.GetCallbackChannel<IMessageCallback>(); 

      //If they exist in the list of subscribers they are then removed 
      if (subscribers.Contains(callback)) 
       subscribers.Remove(callback); 
      return true; 
     } 
     catch 
     { 
      //Otherwise if an error occurs returns false 
      return false; 
     } 

    } 

Enfin, ce au moment isnt't travaille comme essentiellement lorsqu'un utilisateur est abonné comme boucles par le biais je veux pour filtrer la requête LINQ basée sur les utilisateurs ID utilisateur:

#region IMessageCheck Members 

     /// <summary> 
     /// This method checks for new messages recieved based on those who have subscribed for the service 
     /// </summary> 
     public void MessageCheck() 
     { 
      //A continuous loop to keep the method going 
      while(true) 
      { 
       //Changes the thread to a sleep state for 2 mins? 
       Thread.Sleep(200000); 

       //Go through each subscriber based on there callback information 
       subscribers.ForEach(delegate(IMessageCallback callback) 
       { 
        //Checks if the person who wanted the callback can still be communicated with 
        if (((ICommunicationObject)callback).State == CommunicationState.Opened) 
        { 
         //Creates a link to the database and gets the required information 
         List<Mess> mess = new List<Mess>(); 
         List<Message> me; 
         List<MessageLink> messLink; 

         AnnouncementDBDataContext aDb = new AnnouncementDBDataContext(); 

         me = aDb.Messages.ToList(); 
         messLink = aDb.MessageLinks.ToList(); 

         //Query to retrieve any messages which are newer than the time when the last cycle finished 
         var result = (from a in messLink 
             join b in me 
              on a.UniqueID equals b.UniqueID 
             where b.TimeRecieved > _time 
             select new { b.UniqueID, b.Author, b.Title, b.Body, b.Priority, a.Read, b.TimeRecieved }); 

         //Foreach result a new message is created and returned to the PC that subscribed 
         foreach (var a in result) 
         { 
          Mess message = new Mess(a.UniqueID, a.Author, a.Title, a.Body, a.Priority, (bool)a.Read, a.TimeRecieved); 
          callback.OnNewMessage(message); 
         } 
        } 
        //If the requesting PC can't be contacted they are removed from the subscribers list 
        else 
        { 
         subscribers.Remove(callback); 
        } 
       }); 

       //Sets the datetime so the next cycle can measure against to see if new messages have been recieved 
       _time = DateTime.Now; 
      } 

     } 
     #endregion 

Répondre

4

Il y a plusieurs façons d'accomplir ceci. Considérant que vous utilisez une liste statique pour maintenir vos abonnés, vous pouvez générer un nouvel objet comme ceci:

class Subscriber 
{ 
    public string UserName { get; set; } 
    public IMessageCallback CallBack { get; set; } 
} 

stocker ensuite vos abonnés dans un List<Subscriber> au lieu d'un objet List<IMessageCallback>.

Vous pouvez ensuite modifier votre méthode Subscribe() pour prendre un paramètre de chaîne pour le nom d'utilisateur. Cela vous permettra d'utiliser votre requête linq to objects pour trouver l'utilisateur auquel vous voulez envoyer un message.

Cette technique pourrait fonctionner pour n'importe quel identifiant, mais je ne suis pas sûr de la façon dont vous essayez de filtrer les messages. On dirait que vous le voulez par nom d'utilisateur, c'est pourquoi j'ai utilisé cette option ici. Mais vous pouvez tout aussi bien avoir un drapeau Enum pour les types d'abonnements et le transmettre.

Si vous voulez une alternative au stockage de vos abonnés dans une liste statique, vous pouvez consulter un article que j'ai écrit sur Throttling WCF que je utilisez GenericDelegates. Cela pourrait vous donner plus d'options et d'idées. http://www.codeproject.com/KB/WCF/wcfesb.aspx. Cet article vous montrera également un moyen plus simple de maintenir les abonnés que de vérifier l'état du contexte à chaque appel.

+0

Merci beaucoup pour vos idées, lisez votre article et cela correspond à ce que je cherche à faire merci. – manemawanna

1

Vous pouvez utilisez un DuplexChannel. Pour cela, vous devez fournir une liaison qui prend en charge la communication de session et la communication duplex. Ensuite, les clients devront passer un InstanceContext construit avec une instance de CallbackHandler. Enfin, le serveur obtiendra le contexte (pour les messages de rappel), en utilisant:

OperationContext.Current.GetCallbackChannel<ICallBackServiceContract>(); 

où ICallBackServiceContract est le contrat mis en œuvre sur le client.

Pour en savoir plus sur Duplex Services, consultez: Duplex Services

EDIT: Eh bien, si le rappel fonctionne bien, je veux dire que c'est un comportement d'instance. Essayez d'ajouter (ou modifier) ​​la mise en œuvre du contrat, en utilisant le mode par exemple PerSession:

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)] 
+0

Salut merci pour cela, je suis déjà en utilisant un rappel, avec duplex. Ce dont j'ai besoin, c'est de dire qu'un message n'est destiné qu'à un seul utilisateur, il ne devrait aller à cet utilisateur que lorsqu'il s'est abonné plutôt que tout le monde. Je mettrai à jour mon article original pour vous montrer le code que j'ai, bien qu'il ne soit pas encore entièrement terminé. – manemawanna

2

Jetez un oeil à publish-subscribe cadre de WCF Juval Lowy, qui est décrit dans le détail assez bon dans this MSDN article. Le code est disponible à regarder via l'article, ou vous pouvez télécharger la source et l'exemple du site Web de Lowy here. Allez dans la section Téléchargements, filtrez par la catégorie Découverte, et vous le verrez ici. J'utilise ce mécanisme dans mon application WCF, et cela fonctionne comme un charme. J'espère que cela t'aides.

Questions connexes