使用强命名程序集中定义的旧版本接口创建客户端激活对象时的System.InvalidCastException

我有一个关于.Net Remoting,版本控制和创建客户端激活对象的查询。

这是场景:

有2个接口,驻留在它们自己的程序集“SharedTypes”中:IServer和IAccount。 IServer包含返回字符串的方法“GetStatus”和返回IAccount类型的“CreateAccount”。 这是作为v1.0.0.0注册到GAC中的。

服务器应用程序引用SharedTypes并使用具体类Server和Account实现IServer和IAccount。 这些是MarshalByRefObject对象。 Server应用程序将Server类编组为单例对象。

客户端应用程序引用SharedTypes并成功通过IServer接口连接到可远程服务器对象。 在这里,我可以成功调用GetStatus和CreateAccount(它返回一个客户端激活的对象)。 到目前为止一切都好。

现在我将SharedTypes的版本增加到v2.0.0.0并注册到GAC,删除旧的v1.0.0.0版本。

Server应用程序是针对此版本构建的,但客户端不是。

现在,当我运行客户端应用程序时,它会按预期抱怨System.IO.FileNotFoundException,即它无法在GAC中找到v1.0.0.0的SharedTypes。

如果我在客户端的exe目录中复制SharedTypes的v1.0.0.0,则客户端应用程序最终会绑定到此(在GAC查找失败后)。 客户端应用程序启动,我可以成功调用IServer对象上的GetStatus(通过单例对象)。 但是,如果我调用CreateAccount – 它应该返回一个客户端激活的对象,我会得到以下exception:

System.InvalidCastException: Return argument has an invalid type. at System.Runtime.Remoting.Proxies.RealProxy.ValidateReturnArg(Object arg, Type paramType) at System.Runtime.Remoting.Proxies.RealProxy.PropagateOutParameters(IMessage msg, Object[] outArgs, Object returnValue) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at SharedTypes.IServer.GetAccount() 

我的问题是为什么在服务器上调用GetStatus从客户端(使用v1.0.0.0)激活单例对象不会抛出此exception,而通过CreateAccount创建客户端激活对象呢? 由于这两种类型都是在服务器上创建的,我认为GetStatus调用会产生相同的exception吗?

CLR通常确保只能将一个特定版本的程序集加载到进程中。 这在这种情况下不起作用,因为CLR有两个副本在工作,一个在服务器上,一个在客户端上。 因此,现在由远程处理基础设施来确保远程类型对象是兼容的。 在你的情况下,这与aplomb有关。 我不确定我在你的上一句话中提出的问题,但是服务器没有意识到客户端中加载的程序集的版本。

需要重新编译客户端。

这可能无法回答您的具体问题,但是您的问题是我在StackOverflow上找到的唯一一个关于一个莫名其妙的InvalidCastException的问题,其中包含一个涉及服务器单例的消息“返回参数有一个无效的类型”。

在我的情况下,我的客户端通过请求服务器的单例(即在服务器上传递给RemotingServices.Marshal()的对象)开始,然后在处理过程中,它碰巧通过其他方法获得对该单例的引用,得到了这个例外。

我通过为顶级对象创建两个远程代理,一个用作单例,一个可以在其他上下文中内部使用来解决它。 也许是因为,在客户端处理过程中,它试图通过与传递给RemotingServices.Marshal()的类型不同的类型来获取对该单例对象的引用。 我还不确定。 但是,为同一个本地对象提供了两个远程代理,一个用作远程单例,另一个用于所有其他内部用途,解决了这个问题。 幸运的是,我有一个无状态的远程代理架构,因此对同一个本地对象有两个没有造成任何麻烦。

编辑:后来,我发现了一个更简单的解决方案,一个不需要两个代理的解决方案 – 使用参数3中代理的实际类型调用RemotingServices.Marshal() ,而不是接口类型。

对我来说,客户端应用程序在.net 4.0上,而服务器应用程序在4.5上运行。 在客户端计算机上安装.net framework 4.5修复了此问题。