我有一个服务器\客户端应用程序需要通过Activator请求两个不同的远程代理。
我遇到了这样一种情况:如果您通过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的方式,但现在这不是我的选择。
答案 0 :(得分: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源码,但我是having issues。