1

我有一个服务器\客户端应用程序,它需要通过激活器请求两个不同的远程代理。

我遇到了一种情况,如果您在Activator.GetObject不创建通道的情况下请求远程对象,然后再创建一个通道并尝试获取一个单独的对象,那么第二个对象将失败。让我展示一个示例应用程序来演示该问题:

这是两个远程对象:

namespace HelloRemoteObject
{
    public class FirstObject : MarshalByRefObject
    {
        public String FirstObjectMethod()
        {
            return "FirstObjectMethod";
        }
    }

    public class SecondaryObject : MarshalByRefObject
    {
        public String SecondObjectMethod()
        {
            return "Secondary object method return string";
        }
    }
}

这是服务器,它只是在特定端口上注册一个 http 服务器通道,然后等待:

public static int Main(string[] args)
{
    // register the channel
    IDictionary properties = new Hashtable
                                    {
                                        {"timeout", 1000},
                                        {"port", 9099}
                                    };

    var serverChannel = new HttpServerChannel(properties, new BinaryServerFormatterSinkProvider());
    ChannelServices.RegisterChannel(serverChannel, false);

    // register two known types
    RemotingConfiguration.RegisterWellKnownServiceType(typeof(FirstObject), "FirstObjectUri", WellKnownObjectMode.Singleton);
    RemotingConfiguration.RegisterWellKnownServiceType(typeof(SecondaryObject), "SecondaryObjectUri", WellKnownObjectMode.Singleton);

    Console.WriteLine("Hit <enter> to exit...");
    Console.ReadLine();
    return 0;
}

这是客户。如果您传入任何参数,那么它将首先注册一个命名通道。然后它将获取两个远程代理并在它们上调用一个方法。如果您不给它任何参数,它将首先获取第一个对象的代理,然后为第二个代理创建一个通道,然后尝试对这两个对象采取行动。

static void Main(string[] args)
{
    var registerChannelFirst = args.Length > 0;
    if(registerChannelFirst)
    {
        Console.WriteLine("Registering channel first");

        RegisterHttpChannel();
    }
    else
    {
        Console.WriteLine("Letting Activator.GetObject register an http client channel by default");
    }

    var firstRemoteObject = (FirstObject)Activator.GetObject(typeof(FirstObject), "http://127.0.0.1:9099/FirstObjectUri");

    if(!registerChannelFirst)
    {
        RegisterHttpChannel();
    }

    var secondRemoteObject = (SecondaryObject)Activator.GetObject(typeof(SecondaryObject), "http://127.0.0.1:9099/SecondaryObjectUri", );

    Console.WriteLine(firstRemoteObject.FirstObjectMethod());
    Console.WriteLine(secondRemoteObject.SecondObjectMethod());
}

private static void RegisterHttpChannel()
{
    // register the channel
    IDictionary properties = new Hashtable
                                    {
                                        {"name" , "ChannelName"}
                                    };
    var clientChannel = new HttpClientChannel(properties, new BinaryClientFormatterSinkProvider());

    ChannelServices.RegisterChannel(clientChannel, false);
}

如果您先注册一个频道,然后再激活,那么一切正常。

让激活器先运行,然后获取第二个对象,然后您会遇到异常。

如果您不尝试激活两个对象,而只是让激活器获取一个对象,那么这也可以。我很想知道这是为什么?

我很好奇,因为假设我不关心通道属性,那么我可以轻松地创建一个通道并完成它,但是,如果一个对象需要在通道上使用超时,但另一个对象确实如此不是,那么我需要创建两个单独的频道。那么有没有办法将对象绑定到通道?

我也知道远程处理已经走上了 wcf 的道路,但这不是我现在的选择。

4

1 回答 1

0

所以我认为这里的解决方案就是总是注册一个频道名称。当我注册频道名称时,输出如下所示(ChannelName是名称的输出ChannelServices.RegisteredChannels

Registering channel first
ChannelName
FirstObjectMethod
Secondary object method return string

如果我在激活器运行后注册通道,它看起来已经创建了自己的内部默认通道

Letting Activator.GetObject register an http client channel by default
http client, ChannelName

Unhandled Exception: System.Runtime.Remoting.RemotingException: System.ArgumentNullException: No message was deserialized prior to calling the DispatchChannelSink.
Parameter name: requestMsg
at System.Runtime.Remoting.Channels.DispatchChannelSink.ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage& responseMsg, ITransportHeaders& responseHeaders, Stream& responseStream)
at System.Runtime.Remoting.Channels.BinaryServerFormatterSink.ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage& responseMsg, ITransportHeaders& responseHeaders, Stream& responseStream)
at System.Runtime.Remoting.Channels.Http.HttpServerTransportSink.ServiceRequest(Object state)
at System.Runtime.Remoting.Channels.SocketHandler.ProcessRequestNow()


Server stack trace:


Exception rethrown at [0]:
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at HelloRemoteObject.FirstObject.FirstObjectMethod()
   at HelloClient.HelloClient.Main(String[] args) in 

所以有些东西对拥有两个注册的 http 频道感到困惑。我会逐步浏览 .net 源代码,但我遇到了问题

于 2012-09-03T16:46:04.860 回答