2008-11-09 7 views
4

J'essaye de migrer mon code de remoting de .net à wcf mais je le trouve difficile. Quelqu'un peut-il m'aider à migrer ce programme basé Remoting simple ci-dessous pour utiliser WCF? Le programme implémente un modèle simple éditeur/abonné où nous avons un seul programme TemperatureProviderProgram que les éditeurs de nombreux TemperatureSubcriberPrograms qui souscrivent à la TemperatureProvider..Net Remoting au défi WCF!

Pour exécuter les programmes:

  1. Copiez le TemperatureProviderProgram et TemperatureSubcriberProgram dans des projets séparés d'application de la console.
  2. Copie à rester classes et interfaces dans un projet commun de bibliothèque de classes puis ajoutez une référence à la bibliothèque System.Runtime.Remoting
  3. Ajouter une référence au projet de bibliothèque de classe des projets d'applications de la console.
  4. Exécutez et exécutez 1 TemperatureProviderProgram et plusieurs TemperatureSubcriberProgram.

Veuillez noter qu'aucun IIS ou XML ne doit être utilisé. Merci d'avance.

public interface ITemperatureProvider 
{ 
    void Subcribe(ObjRef temperatureSubcriber); 
} 

[Serializable] 
public sealed class TemperatureProvider : MarshalByRefObject, ITemperatureProvider 
{ 
    private readonly List<ITemperatureSubcriber> _temperatureSubcribers = new List<ITemperatureSubcriber>(); 
    private readonly Random randomTemperature = new Random(); 

    public void Subcribe(ObjRef temperatureSubcriber) 
    { 
     ITemperatureSubcriber tempSubcriber = (ITemperatureSubcriber)RemotingServices.Unmarshal(temperatureSubcriber); 
     lock (_temperatureSubcribers) 
     { 
      _temperatureSubcribers.Add(tempSubcriber); 
     } 
    } 

    public void Start() 
    { 
     Console.WriteLine("TemperatureProvider started..."); 
     BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider(); 
     provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; 
     TcpServerChannel tcpChannel = new TcpServerChannel("TemperatureProviderChannel", 5001, provider); 
     ChannelServices.RegisterChannel(tcpChannel, false); 
     RemotingServices.Marshal(this, "TemperatureProvider", typeof(ITemperatureProvider)); 

     while (true) 
     { 
      double nextTemp = randomTemperature.NextDouble(); 

      lock (_temperatureSubcribers) 
      { 
       foreach (var item in _temperatureSubcribers) 
       { 
        try 
        { 
         item.OnTemperature(nextTemp); 
        } 
        catch (SocketException) 
        {} 
        catch(RemotingException) 
        {} 
       } 
      } 
      Thread.Sleep(200); 
     } 
    } 
} 

public interface ITemperatureSubcriber 
{ 
    void OnTemperature(double temperature); 
} 

[Serializable] 
public sealed class TemperatureSubcriber : MarshalByRefObject, ITemperatureSubcriber 
{ 
    private ObjRef _clientRef; 
    private readonly Random portGen = new Random(); 

    public void OnTemperature(double temperature) 
    { 
     Console.WriteLine(temperature); 
    } 
    public override object InitializeLifetimeService() 
    { 
     return null; 
    } 

    public void Start() 
    { 
     BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider(); 
     provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; 

     int port = portGen.Next(1, 65535); 
     TcpServerChannel tcpChannel = new TcpServerChannel(string.Format("TemperatureSubcriber_{0}", Guid.NewGuid()), port, provider); 
     ChannelServices.RegisterChannel(tcpChannel, false); 

     ITemperatureProvider p1 = (ITemperatureProvider)RemotingServices.Connect(typeof(ITemperatureProvider), "tcp://localhost:5001/TemperatureProvider"); 
     _clientRef = RemotingServices.Marshal(this, string.Format("TemperatureSubcriber_{0}_{1}.rem", Environment.MachineName, Guid.NewGuid())); 
     p1.Subcribe(_clientRef); 
    } 
} 

public class TemperatureProviderProgram 
{ 
    static void Main(string[] args) 
    { 
     TemperatureProvider tp = new TemperatureProvider(); 
     tp.Start(); 
    } 
} 
public class TemperatureSubcriberProgram 
{ 
    static void Main(string[] args) 
    { 
     Console.WriteLine("Press any key to start TemperatureSubcriber."); 
     Console.ReadLine(); 
     TemperatureSubcriber ts = new TemperatureSubcriber(); 
     ts.Start(); 
     Console.ReadLine(); 
    } 
} 
+0

Remoting et WCF fonctionnent différemment, êtes-vous sûr que cela vaut la peine d'essayer de migrer le code? – Sekhat

+0

Est-ce une question de devoirs? – Andrew

Répondre

1

Vous devrez modifier légèrement votre logique. Si vous souhaitez migrer cette application vers WCF. Vous devrez demander aux clients d'extraire les données du service à intervalles réguliers.

Vous aurez également besoin d'un service ou d'une application Windows pour héberger le WCF comme la console que vous utilisez dans le code précédent.

+1

En fait, WCF prend en charge le duplex pour le serveur qui pousse vers le client. Je ne le ferais pas moi-même, cependant. –

+1

vrai, mais je ne suis pas sûr si c'est le meilleur modèle à utiliser pour quelque chose comme ça. Je ne connais pas le volume de clients que cela est supposé supporter. –

+0

WCF a des canaux duplux, mais ils ont beaucoup de problèmes, alors utilisez l'interrogation si vous pouvez vous en sortir. –

1

Dans WCF, avec un « push » du serveur que vous parlez vraiment duplex comms; le MarshalByRefObject est largement redondant ici (AFAIK). La page here traite de divers scénarios, y compris les duplex/callbacks.

Si le problème est de type xml (pour une raison philosophique), il peut être utile d'utiliser simplement NetDataContractSerializer plutôt que DataContractSerializer.

L'autre approche est d'avoir les clients des données « pull » périodiquement; cela fonctionne bien si vous avez besoin pour soutenir http de base, etc.

0

Eh bien, je construire des systèmes en temps réel si l'interrogation est pas une option - je dois pousser des données.

Aussi je trouve qu'il n'y a pas d'équivalent WCF de System.Runtime.Remoting.ObjRef! Il s'agit d'un type extrêmement utile qui encapsule un point de terminaison de service et peut être sérialisé et transmis sur le réseau à un autre service distant.

pense que je vais coller avec bon vieux Remoting jusqu'à ce que l'équivalent ObjRef est introduit.

1

Ce qu'il semble que vous voulez faire est d'utiliser WCF NetTcpBinding avec Callbacks.

Jetez un oeil à ceci: http://www.codeproject.com/KB/WCF/publisher_subscriber.aspx

"Learning WCF" par Michele Bustamante est également très bon. Vous pouvez obtenir Chpt1 pour VS2008 sur son site Web avec le code pour le livre. Chpt1 va expliquer/démo configurer des connexions et autres. Elle a également un exemple de code téléchargeable. L'un des exemples est un DuplexPublishSubscribe.

0

Oui c'est vrai, juste une correction .. ObjRefs sont créés automatiquement lorsque n'importe quel objet dérivé de MarshalByRefObject sort du domaine. Donc, dans ce cas, votre méthode d'abonnement ITemperatureProvider doit prendre la propriété ITemperatureSubscriber au lieu de objref. Ensuite, côté client, appelez simplement p1.Subscribe (this) et la couche distante générera ObjRef à partir de l'objet qui sera sérialisé et envoyé. (envoi de la référence b)