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

C# 使用强名称程序集中定义的接口的旧版本创建客户端激活的对象时System.InvalidCastException,c#,.net,visual-studio-2010,client-server,.net-remoting,C#,.net,Visual Studio 2010,Client Server,.net Remoting,我有一个关于.Net远程处理、版本控制和创建客户端激活对象的问题 以下是场景: 有两个接口驻留在它们自己的程序集“SharedTypes”中:IServer和IAccount。IServer包含返回字符串的方法“GetStatus”和返回IAccount类型的方法“CreateCount”。这在GAC中注册为v1.0.0.0 服务器应用程序引用共享类型,并使用具体的类、服务器和帐户实现IServer和IAccount。这些是MarshalByRefObject对象。服务器应用程序将服务器类封送为

我有一个关于.Net远程处理、版本控制和创建客户端激活对象的问题

以下是场景:

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

服务器应用程序引用共享类型,并使用具体的类、服务器和帐户实现IServer和IAccount。这些是MarshalByRefObject对象。服务器应用程序将服务器类封送为单例对象

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

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

服务器应用程序是根据此版本生成的,但客户端不是

现在,当我运行客户端应用程序时,它会像预期的那样抱怨System.IO.FileNotFoundException,即在GAC中找不到1.0.0.0版的共享类型

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

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()

我的问题是,为什么从客户端(使用v1.0.0.0)调用服务器激活的singleton对象上的GetStatus不会引发此异常,而通过CreateCount创建客户端激活的对象会引发此异常?由于这两种类型都是在服务器上创建的,我本以为GetStatus调用会导致相同的异常?

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


需要重新编译客户端。

这可能无法回答您的特定问题,但您的问题是我在StackOverflow上找到的唯一一个关于无法解释的InvalidCastException的问题,消息为“Return argument has a invalid type”,涉及服务器单例

在我的例子中,我的客户机首先请求服务器的单例(即在服务器上传递给的对象),然后在处理过程中,它碰巧通过其他方法获得了对该单例的引用,并获得了此异常

我通过为顶级对象创建两个远程代理来解决这个问题,一个用作单例,另一个可在其他上下文中内部使用。可能是因为,在客户端处理过程中,它试图通过与传递给的类型不同的类型获取对该单例对象的引用。我还是不确定。但是对于同一个本地对象有两个远程代理,一个用作远程处理单例,另一个用于所有其他内部目的,解决了这个问题。幸运的是,我有一个无状态远程代理体系结构,所以对于同一个本地对象有两个代理并没有引起任何问题


编辑:后来,我找到了一个更简单的解决方案,它不需要两个代理——在参数3中使用代理的实际类型而不是接口类型进行调用。

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

谢谢Hans,我已编辑了此问题,希望更容易理解。我们通过使用发布者策略程序集来避免重新编译客户端,这很好地解决了这个问题。但是,我很想知道为什么这个特定场景会导致客户端引用旧版本的强名称程序集,成功地在服务器应用程序中调用服务器激活的远程对象上的方法引用新版本的强名称程序集,但无法创建客户端激活的对象。