【问题标题】:.NET Remoting: how to access server application objects from remotable object?.NET Remoting:如何从远程对象访问服务器应用程序对象?
【发布时间】:2009-01-19 05:39:32
【问题描述】:

我正在编写一个 Windows 服务应用程序,它将通过 .NET Remoting 访问。 问题是我不知道如何从远程类访问服务对象。

例如,我有一个处理程序类:

class Service_console_handler
   {
    public int something_more = 20;

    //some code...

            TcpChannel serverChannel = new TcpChannel(9090);
            ChannelServices.RegisterChannel(serverChannel);
            RemotingConfiguration.RegisterWellKnownServiceType(
                        typeof(RemoteObject), "RemoteObject.rem", 
                        WellKnownObjectMode.Singleton);

    //from here on RemoteObject is accessible by clients.
    //some more code doing something and preparing the data...
   }

我有一个远程类:

public class RemoteObject : MarshalByRefObject
{
    private int something = 10;

    public int Get_something()
    {
        return something;
    }
}

客户端可以毫无问题地访问 RemoteObect 中的数据。但是如何访问Service_console_handler 对象(即从something_more 检索有用信息)?

很抱歉提出愚蠢的问题,提前致谢。

【问题讨论】:

    标签: c# .net remoting


    【解决方案1】:

    您想要通过RemoteObject 实例以某种方式访问​​ServiceConsoleHandler 的实例,该实例对客户端可见。

    为此,您需要考虑两件事:(1) 控制RemoteObject 实例的对象构造并使其可访问;(2) 修改ServiceConsoleHandler 使其可远程访问。

    (1)

    如果您不需要考虑远程处理,您将如何在ServiceConsoleHandler 中构造RemoteObject 实例?

    我猜你会这样做:

    class ServiceConsoleHandler
    {
       …
       RemoteObject remoteObject = new RemoteObject();
       // now assume that you also already have
       // modified the RemoteObject class so it can hold
       // a reference to your server:
       remoteObject.Server = this;
       …
    }
    

    如果您可以使该对象可供客户端访问,那就太好了。您可以使用RemotingServices.Marshal 而不是 RemotingConfiguration.RegisterWellKnownServiceType 来做到这一点:

    class ServiceConsoleHandler
    {
         …
         TcpServerChannel channel = new TcpServerChannel(9090);
         ChannelServices.RegisterChannel(channel, true);
         RemoteObject remoteObject = new RemoteObject();
         remoteObject.Server = this;
         RemotingServices.Marshal(remoteObject, "RemoteObject.rem");
         …
    }
    

    (2)

    如果您现在执行代码并访问客户端代码中的remoteObject.Server,您会得到一些远程处理异常,因为无法远程访问类ServiceConsoleHandler。因此您需要添加[Serializable] 属性:

    [Serializable]
    class ServiceConsoleHandler
    { … }
    

    原因:应该远程访问的类型需要编组为一些特殊的可传输表示。这样它们就可以通过 TCP 端口被挤压并通过 TCP 协议传输。基本数据类型可以由框架编组,因此您无需考虑它们。对于自定义类型,您需要说明如何执行此操作。一种方法是从MarshalByRefObject 继承。这正是您对RemoteObject 所做的。另一种方法是将您的自定义类标记为[Serializable],如上所示。

    就是这样。现在您应该能够访问客户端代码中的服务器字段。请注意,您不需要现有代码来激活对象:

            TcpClientChannel channel = new TcpClientChannel();
            ChannelServices.RegisterChannel(channel, true);
    
            RemoteObject remoteObject = (RemoteObject)Activator.GetObject(
                typeof(RemoteObject), "tcp://localhost:9090/RemoteObject.rem");
    
            Console.WriteLine(remoteObject.Server.SomethingMore);
    

    对我来说,.NET 远程处理充满了有趣的惊喜和不眠之夜。为了解决这个问题,请让自己熟悉远程处理概念(从我的角度来看,这些概念记录得很少)。深入研究序列化概念(MarshalByRefObject[Serializable])。如果您想从中制作生产代码,请考虑一种处理远程异常的非常好的方法。还要考虑多线程。一次可能有多个客户端使用此远程对象。

    玩得开心!

    【讨论】:

      【解决方案2】:

      谢谢!我非常感谢您回答的彻底和清晰。

      最奇怪的是我什至不知道你可以发布对象实例。我研究的大约十几个简单教程建议将RemotingConfiguration.RegisterWellKnownServiceType 作为进行远程处理的唯一方法。真傻。

      现在远程处理对我来说更有用了。我刚刚写了一个快速测试应用程序,它工作。再次感谢。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多