IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Communication Foundation .NET Discussion :

Comment faire communiquer l'hôte avec le service ?


Sujet :

Windows Communication Foundation .NET

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut Comment faire communiquer l'hôte avec le service ?
    Bonjour,

    Je souhaite développer une application de test/debug qui héberge l'implémentation d'un service WCF.

    Voici un bout de code pour présenter un exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
        // Déclaration de l'interface contrat
        [ServiceContract(SessionMode = SessionMode.Required)]
        public interface IService1
        {
            [OperationContract]
            string Hello(string message);
        }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
        // Classe implémentant l'interface de contrat
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
        public class Service1 : IService1
        {
            public Service1()
            { }
     
            public string Hello(string message)
            {
                return "Hello " + message;
            }
        }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
        // IHM en WPF
        public partial class MainWindow : Window
        {
            private ServiceHost _Host1;
     
    private void Start_OnClick(object sender, RoutedEventArgs e)
            {
                _Host1 = new ServiceHost(typeof(Service1));
     
                _Host1.Opening += HostOnOpening;
                _Host1.Opened += HostOnOpened;
                _Host1.Closing += HostOnClosing;
                _Host1.Closed += HostOnClosed;
     
                try
                {
                    _Host1.Open();
                    btStart.IsEnabled = false;
                    lbJournal.Content += "\nService démarré";
                }
                catch (Exception ex)
                {
                    btStart.IsEnabled = true;
                    lbJournal.Content += "\nService ne peut pas démarrer" + ex.Message;
                }
            }
     
    // ....
        }
    Mon but est d'afficher dans l'interface principale un certain nombre d'informations côté serveur lorsqu'un client se connecte ou communique avec le serveur afin de pouvoir monitorer ce qui se passe.

    J'ai récupéré les événements de connexion/déconnexion de l'hôte, mais mon problème est pour trouver comment faire communiquer les instances de Service1 avec l'hôte.

    Comme je suis en Session Required, je ne peux pas créer un singleton et le passer à l'hôte. Les instances de Service1 sont automatiquement instanciées et je ne trouve pas de moyen pour les récupérer.

    Il existerait un moyen, ce serait de déclarer une sorte d'intermédiaire global qui serait utilisé par la classe Service1 quand elle s'instancie et aussi par l'hôte mais je ne trouve pas cette solution très propre.

    Est-ce que ma demande est prévue et supportée par WCF ou doit-on faire une solution plus "bidouille" ?

    Merci par avance pour votre aide.

  2. #2
    Invité
    Invité(e)
    Par défaut
    Une solution pas très clean mais que je pense répond à ton besoin.

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    [ServiceContract(SessionMode = SessionMode.Required)]
    public interface IService1
    {
        [OperationContract(IsInitiating=true)]
        void Start();
     
        [OperationContract(IsTerminating = true)]
        void End();
     
        [OperationContract]
        string Hello(string message);
    }
     
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class Service1 : IService1
    {
     
        public static System.Collections.Concurrent.ConcurrentBag<IService1> ServiceInstances { get; private set; }
     
        static Service1()
        {
            ServiceInstances = new System.Collections.Concurrent.ConcurrentBag<IService1>();
        }
     
        public void Start()
        {
            ServiceInstances.Add(OperationContext.Current.InstanceContext.GetServiceInstance() as IService1);
        }
     
        public void End()
        {
            IService1 service1 = OperationContext.Current.InstanceContext.GetServiceInstance() as IService1;
            OperationContext.Current.InstanceContext.ReleaseServiceInstance();
            ServiceInstances.TryTake(out service1);
        }
     
        public string Hello(string message)
        {
            return "Hello " + message;
        }        
    }

    Ma solution oblige tous les clients à d'abords faire appel à l'opération Start (qui permet de savoir qu'un client vient d'accéder au service et ainsi de l'ajouter à notre collection) et faire appel à l'opération End (qui permet de nettoyer notre collection). La collection est statique et publique donc peut être accédée sans problème.

    Ma solution n'est pas clean parce qu'on n'est pas sûr à 100% que le client fasse appel à la méthode End (pour Start c'est sûr sinon impossible de continuer la communication avec le service). Imagine qu'il y ait un problème réseaux et qu'on perde la connexion alors le client n'a pas appelé la méthode End alors la collection risque d'être polluée vu que le nettoyage ne sera pas effectué. Le même problème se pose quand la durée maximale d'inactivité est atteinte (InactivityTimeout) et que le client est déconnecté de façon automatique.

  3. #3
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    Salut,

    j'ai une question sur ta solution. Pourquoi dans les méthodes Start et End tu utilises
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    OperationContext.Current.InstanceContext.GetServiceInstance() as IService1
    au lieu de this ?

    Vu que Service1 n'est instancié qu'une fois par session, ne peut-on pas rajouter l'instance depuis le constructeur et non pas la méthode Start et la retirer dans le destructeur et non pas la méthode End ?
    Ainsi, on n'aurait plus la problématique de la coupure de la session alors que la méthode End n'est pas appelée.

  4. #4
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    Salut, je viens de découvrir un élément bizarre sur la méthode TryTake de la classe ConcurrentBag; son paramètre est en out, c'est uniquement un paramètre de sortie et non d'entrée.

    Ce qui veut dire qu'on ne peut pas spécifier l'élément qu'on souhaite retirer de la collection.

    Ce n'est pas très grave, je vais utiliser une Liste en private et faire des lock sur chacun de ses appels.

    Voici la référence de la MSDN :
    http://msdn.microsoft.com/fr-fr/libr...v=vs.100).aspx

  5. #5
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par WebPac Voir le message
    j'ai une question sur ta solution. Pourquoi dans les méthodes Start et End tu utilises
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    OperationContext.Current.InstanceContext.GetServiceInstance() as IService1
    au lieu de this ?

    Vu que Service1 n'est instancié qu'une fois par session, ne peut-on pas rajouter l'instance depuis le constructeur et non pas la méthode Start et la retirer dans le destructeur et non pas la méthode End ?
    Ainsi, on n'aurait plus la problématique de la coupure de la session alors que la méthode End n'est pas appelée.
    Je n'ai pas eu le temps de tester ce que tu as dit dans le message ci-dessous.
    Vu qu'on est en InstanceContextMode = InstanceContextMode.PerSession donc cela veut dire qu'on aura une instance du service par session. Donc la solution avec le this devrait pouvoir marcher (mais j'ai comme un doute que ce ne sera pas le cas). As-tu testé de ton côté ?

  6. #6
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    L'utilisation de this paraît fonctionner correctement.

    Je n'utilise plus une CollectionBag<T> mais une List<T> private avec un lock sur chacun de ses appels.

    J'ai rajouté l'instance Service1 dans la liste depuis le constructeur, ça fonctionne.
    J'ai retiré l'instance Service1 de la liste depuis le destructeur, ça ne fonctionne pas, malgré une GarbageCollection.
    Je n'ai pas encore testé pour voir si c'est le destructeur qui n'est pas appelé.

    Une chose me chagrine tout de même, je travaille en session, mais je peux appeler toute méthode qui n'initialise pas la session en premier et ça fonctionne bien.

  7. #7
    Membre éclairé Avatar de WebPac
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    947
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 947
    Par défaut
    En utilisant le méthode avec IsTerminating = true, ça fonctionne.
    Je marque en résolu.

    Merci pour ton aide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comment faire communiquer Flex avec un JDBC svp?
    Par takinelinfo dans le forum Flash
    Réponses: 2
    Dernier message: 30/10/2009, 16h23
  2. Réponses: 3
    Dernier message: 06/07/2009, 12h11
  3. Comment faire communiquer C++ avec J2EE
    Par FST_PFE dans le forum Débuter avec Java
    Réponses: 14
    Dernier message: 16/05/2008, 17h49
  4. Réponses: 3
    Dernier message: 27/07/2006, 10h17
  5. Je suis un gros boulet ou comment faire de la 2D avec DX
    Par Freakazoid dans le forum DirectX
    Réponses: 4
    Dernier message: 19/06/2004, 16h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo