System.InvalidCastException when creating a client activated object using an older version of an interface defined in a strong named assembly

和自甴很熟 提交于 2019-12-17 21:32:49

问题


I have a query about .Net Remoting, versioning and creating client activated objects.

Here is the scenario:

There are 2 interfaces, residing in their own assembly “SharedTypes”: IServer and IAccount. IServer contains methods “GetStatus” which returns a string, and “CreateAccount” which returns an IAccount type. This is registered into the GAC as v1.0.0.0.

Server application references SharedTypes and implements IServer and IAccount with concrete classes, Server and Account. These are MarshalByRefObject objects. The Server application marshals the Server class as a singleton object.

Client application references SharedTypes and connects to the remoteable Server object through the IServer interface successfully. Here I can call GetStatus and CreateAccount (which returns a client activated object) successfully. All OK so far.

Now I increment the version of SharedTypes to v2.0.0.0 and register into the GAC, removing the old v1.0.0.0 version.

The Server application is built against this version, but the client is not.

Now when I run the client application, it will as expected complain with a System.IO.FileNotFoundException, i.e. it could not find v1.0.0.0 of SharedTypes in the GAC.

If I copy v1.0.0.0 of SharedTypes in the exe directory of the client, the client application eventually binds to this (after GAC lookup was unsuccessful). The client application starts and I can call the GetStatus on the IServer object successfully (through the singleton object). However, if I call CreateAccount – which should return a client activated object, I get the following 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()

My question is why does calling GetStatus on the server activated singleton object from the client (which is using v1.0.0.0) not throw this exception, whereas creating the client activated object through CreateAccount does? Since both types are created on the server, I would have thought that GetStatus call would have resulted in the same exception?


回答1:


The CLR normally ensures that only one specific version of an assembly can be loaded into a process. That doesn't work in this scenario because there are two copies of the CLR at work, one on the server and one on the client. So now it is up to the remoting infrastructure to ensure that remoted type objects are compatible. Which is does with aplomb in your case. Not sure I got the question posed in your last sentence but the server is not otherwise aware of the version of the assembly loaded in the client.

Recompiling the client is required.




回答2:


This may not answer your specific question, but yours is the only question I can find on StackOverflow regarding an inexplicable InvalidCastException with the message "Return argument has an invalid type" involving a server singleton.

In my case, my client started by requesting the server's singleton (i.e. the object that was passed to RemotingServices.Marshal() on the server), then in the course of its processing, it happened to get a reference to that singleton via other methods, and got this exception.

I worked around it by creating two remote-proxies for the top-level object, one to serve as the singleton, and one that could be used internally in other contexts. Perhaps it's because, in the course of client processing, it tried to get a reference to that singleton object through a different type than the one that was passed to RemotingServices.Marshal(). I'm still not sure. But having two remote-proxies for the same local object, one to serve as a remoting singleton, and one for all other internal purposes, worked around the problem. Luckily I have a stateless remote-proxy architecture, so having two for the same local-object didn't cause any trouble.

Edit: Later, I found a simpler solution, one that doesn't require two proxies -- call RemotingServices.Marshal() with the actual type of the proxy in parameter 3, instead of the interface type.




回答3:


For me, client application was on .net 4.0 while server app was running on 4.5. Installing .net framework 4.5 on client machine fixed this issue.



来源:https://stackoverflow.com/questions/7040355/system-invalidcastexception-when-creating-a-client-activated-object-using-an-old

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!