Remoting was designed to work with strong-named assemblies. When strong names are used with remoting, the following basic rules apply:
- Versions are always included with the TypeName property of an IMethodCallMessage interface implementation.
- Versions are always included with the ActivationTypeName property of an IConstructionCallMessage interface implementation.
- Versions are always included with the TypeInfo property stored in ObjRef objects.
- All other versioning in remoting is determined by the includeVersions property of the formatter in use. By default, the BinaryFormatter object generates versioning information but the SoapFormatter object does not. This property can be changed programmatically when a channel is created or it can be set through the remoting configuration file.
This section describes how these rules affect object references and the different activation models commonly used in remoting.
The server controls which version of a type is activated when a client connects to a server-activated (or <wellknown>) object. If no version information is provided when the service is configured, the most recent version of the assembly is used when the object is activated. For example, if you have two assemblies, MyHello version 188.8.131.52 and MyHello version 184.108.40.206, the well-known object is activated using the version 2 assembly if no version information is provided. It is important to note that this version is used irrespective of the version referenced when the client was built.
The service can be configured to use a specific version of an assembly. For example, the following configuration file shows how to specify a version. Note that if an assembly is in the global assembly cache, you must specify all type information, including culture information and the public key. The following configuration examples omit the strong name information to concentrate on versioning.
<configuration> <system.runtime.remoting> <application name="RemotingHello"> <lifetime leaseTime="20ms" sponsorshipTimeOut="20ms" renewOnCallTime="20ms" /> <service> <wellknown mode="SingleCall" type="Hello.HelloService,MyHello,Version=220.127.116.11,<strong name omitted>" objectUri="HelloService.soap" /> <activated type="Hello.AddService, MyHello" /> </service> <channels> <channel port="8000" ref="tcp" > </channel> </channels> </application> </system.runtime.remoting> </configuration>
This file specifies that Version 18.104.22.168 of the
MyHello assembly should be used to create objects for its clients. When more than one version of the same object is specified at the endpoint, the last version specified is used when the object is activated. It is important to remember that any significant changes between versions of the same object can have an adverse effect on clients. If a method parameter is added or modified between versions, clients compiled against version 1 will throw an exception when used against version 2. Therefore, it is recommended that a new version of an object be hosted at a different endpoint when any significant changes have occurred between versions.
When a client activates a client-activated (that is, an <activated>) object, a network call is immediately sent to the server where the requested object is activated and an object reference to the object is returned to the client. Because it directs the activation of the object, the client also chooses the version of the object to be activated. For example, version 1 of HelloService will be activated on the server if the client was built against version 1 of the object, and version 2 of HelloService will be activated on the server if the client was built against version 2.
It is important to note that you cannot specify the version number for client-activated types when configuring the service. Also, any versioning information provided for server-activated types has no effect on client-activated objects, even if both types are in the same assembly.
For example, suppose you have a client-activated type and a server-activated type in the same assembly, and you build client1 against version 1 and client2 against version 2. If no version information is specified for the server-activated object, client1 will receive version 2 of the server-activated object and version 1 of the client activated object. Client2 will receive version 2 objects for both well-known and activated types.
If you configure the service to use version 1 of the assembly for the well-known object, both clients will receive version 1 of the well-known object while client 1 receives version 1 of the activated type and client 2 receives version 2 of the activated type.
The version activated for a client cannot be configured; the version the client was built against is always used.
The same rules that apply to server-activated and client-activated types apply to object references as well. For example, when a proxy for a client-activated type is passed as a parameter from one client to another, or from a client to the server, the version information embedded in the object reference is passed with it. When the receiver attempts to call a method on the proxy generated from the object reference, the version embedded in the object reference takes precedence over the version the client was built against. In the case of server-activated objects, the server dictates the version that will be used and all clients that receive an object reference as a parameter communicate with the version specified when the service was configured. In the absence of any versioning, the latest version is activated on the server.
When a marshal-by-value (MBV) object is passed between application domains, the formatter used determines whether version information is included. BinaryFormatter objects always include the version, while SoapFormatter object ignore version information. This option can be enabled or disabled for both formatters. For example, if the following line is added to the configuration file, the SoapFormatter adds versioning information when it serializes an object.
<formatter ref="soap" includeVersions="true" />