4

.net リモーティング コードを wcf に移行しようとしていますが、難しいと感じています。以下の単純なリモート ベースのプログラムを WCF を使用するように移行するのを手伝ってくれる人はいますか? このプログラムは、TemperatureProvider にサブスクライブする多くの TemperatureSubcriberPrograms に発行する単一の TemperatureProviderProgram を持つ単純なパブリッシャー/サブスクライバー パターンを実装します。

プログラムを実行するには:

  1. TemperatureProviderProgram と TemperatureSubcriberProgram を別のコンソール アプリケーション プロジェクトにコピーします。
  2. 残りのクラスとインターフェイスを共通のクラス ライブラリ プロジェクトにコピーしてから、System.Runtime.Remoting ライブラリへの参照を追加します。
  3. コンソール アプリ プロジェクトからクラス ライブラリ プロジェクトへの参照を追加します。
  4. 1 つの TemperatureProviderProgram と複数の TemperatureSubcriberProgram をコンパイルして実行します。

IIS または xml は使用しないでください。前もって感謝します。

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();
    }
}
4

5 に答える 5

1

ロジックを少し変更する必要があります。このアプリをに移行する場合WCF。クライアントに定期的にサービスからデータをプルさせる必要があります。

WCF前のコードで使用しているコンソールなどをホストするには、Windowsサービスまたはアプリケーションも必要です。

于 2008-11-10T09:16:15.810 に答える
1

WCFでは、サーバーからの「プッシュ」により、実際には二重通信について話していることになります。ここでMarshalByRefObjectはほとんど冗長です(AFAIK)。このページでは、デュプレックス/コールバックを含むさまざまなシナリオについて説明しています。

問題がxmlである場合(哲学的な理由で)、役立つNetDataContractSerializerのではなく単に使用することDataContractSerializerが役立つ場合があります。

もう1つのアプローチは、クライアントに定期的にデータを「プル」させることです。これは、基本httpなどをサポートする必要がある場合にうまく機能します。

于 2008-11-10T09:18:10.097 に答える
1

あなたがやりたいように聞こえるのは、コールバックで WCF NetTcpBinding を使用することです。

これを見てください: http://www.codeproject.com/KB/WCF/publisher_subscriber.aspx

Michele Bustamante による「Learning WCF」も非常に優れています。VS2008 の Chpt1 は、彼女の Web サイトで本のコードと共に入手できます。Chpt1 では、接続の設定などについて説明/デモを行います。また、ダウンロード可能なサンプル コードもあります。サンプルの 1 つは DuplexPublishSubscribe です。

于 2008-12-11T14:32:26.977 に答える
0

はい、本当です。1 つだけ訂正があります。ObjRef は、MarshalByRefObject 派生オブジェクトが appdomain の外に出たときに自動的に作成されます。したがって、この場合、ITemperatureProvider インターフェイスの Subscribe メソッドは、objref の代わりに ITemperatureSubscriber を使用する必要があります。次に、クライアント側で p1.Subscribe(this) を呼び出すだけで、リモーティング レイヤーは、シリアル化されて送信されるオブジェクトから ObjRef を生成します。(送信 b 参照)

于 2009-01-08T14:02:47.460 に答える
0

私はリアルタイム システムを構築しているので、ポーリングはオプションではありません。データをプッシュする必要があります。

また、System.Runtime.Remoting.ObjRef に相当する WCF がないことがわかりました。これは、サービス エンドポイントをカプセル化する非常に便利なタイプであり、シリアル化して、ネットワークを介して他のリモート サービスに渡すことができます。

ObjRef に相当するものが導入されるまで、私は古き良きリモーティングに固執すると思います。

于 2008-11-10T13:25:45.900 に答える