4

我正在尝试将我的 .net 远程处理代码迁移到 wcf,但我发现它很困难。有人可以帮我迁移下面这个基于远程处理的简单程序以使用 WCF 吗?该程序实现了一个简单的发布者/订阅者模式,其中我们有一个 TemperatureProviderProgram,它发布到许多订阅 TemperatureProvider 的 TemperatureSubcriberProgram。

要运行程序:

  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. 您需要让客户端定期从服务中提取数据。

您还需要一个 Windows 服务或应用程序来托管WCF您在前面代码中使用的控制台。

于 2008-11-10T09:16:15.810 回答
1

在 WCF 中,通过服务器的“推送”,您实际上是在谈论双工通信;这MarshalByRefObject在很大程度上是多余的(AFAIK)。此处的页面讨论了各种场景,包括双工/回调。

如果问题是 xml(出于某种哲学原因),那么简单地使用NetDataContractSerializer而不是DataContractSerializer可能会有所帮助。

另一种方法是让客户端定期“拉”数据。如果您需要支持基本的 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 以及本书的代码。Chpt1 将解释/演示设置连接等。她还有可下载的示例代码。其中一个示例是 DuplexPublishSubscribe。

于 2008-12-11T14:32:26.977 回答
0

是的,这是真的,只是一个更正。当任何 MarshalByRefObject 派生对象超出 appdomain 时,会自动创建 ObjRefs。因此,在这种情况下,您的 ITemperatureProvider 接口订阅方法应该采用 ITemperatureSubscriber 而不是 objref。然后在客户端只需调用 p1.Subscribe(this) ,远程处理层将从将被序列化和发送的对象生成 ObjRef。(发送b参考)

于 2009-01-08T14:02:47.460 回答
0

好吧,我构建了实时系统,所以轮询不是一种选择——我需要推送数据。

另外我发现没有与 System.Runtime.Remoting.ObjRef 等效的 WCF!这是一种非常有用的类型,它封装了一个服务端点,可以序列化并通过网络传递给其他远程服务。

认为在引入等效的 ObjRef 之前,我会坚持使用旧的远程处理。

于 2008-11-10T13:25:45.900 回答