Welcome to MSDN Blogs Sign in | Join | Help

This is probably not a very wellknown fact, but static methods and fields accessed via a remoting proxy, are actually executed locally on the client side. So even though a type is configured to go remote static accesses/invokations dont go remote.

If you need to access static data on the server side, you need to wrap the static access with instance methods / properties or fields.

Infact they could. The contract for a remoting singleton wellknown object is that "a" object would always be available on the remoting wellknown endpoint. It doesnt mean the same single instance is always available. Singletons also follow the same leasing behaviour like client-activated objects. They would be cleaned up if the lease on a particular instance expires. If a client requests arrives after a singleton has been GCed a new object will be instantiated.

This little caveat is important for stateful singletons since a lease expiry could mean loss of state. To make a singleton live forever (forever: life of the appdomain) set its lease to infinite.

Each remoting channel has a priority associated with it. If there are multiple channels registered in the same appdomain and a MarshalByRefObject is marshalled out, all available channel data will flow with the ObjRef. The order is which this channel data is placed depends on the priority of the channel. You could change the priority of the channel using "priority" entry in configuration or through the IDictionary.

When the ObjRef is deserialized on the client side, each registered client channel will be queried to see if it could handle any of the URLs in the available channelData. Thus the channel with higher priority will get used if it is available on the client. So adjusting priorities can let you choose what channel gets used on the client.

Got an interesting question about how to deserialize delegates serialized with an older version of an assembly. While deserializing, if the older version isnt available the engine might throw a TypeLoadException. The Serialization binder doesnt help in this case since Delegate holders implement IObjectReference and are serialized as simple type and method names (the holder itself is loaded fine). During deserialization IObjectReference.GetRealObject creates and binds the appropriate delegate, which fails if the correct assembly couldnt be loaded. 

The solution is to use AssemblyResolve event and load the appropriate assembly and the delegate would be deserialized as expected.

Note: Serializing delegates could lead to security issues, since a method of the same signature can be invoked if the serialized stream is modified. Thus be careful while serializing/deserializing delegates when you are deserializing from untrusted sources.

A remoting client need not register a channel (if its http or tcp) when making a remote call. The remoting infrastructure will load an appropriate channel after looking at the scheme of the URL (tcp:// or http://). Though being explicit in code is goodness for the channel case it can lead to unwanted results in some scenarios, eg. If the client is hosted in a IIS vroot and it doesnt have control over other components which might be loaded in the same appdomain. Though you could protect against channel registration failing by giving your channel a unique name, you should be able to get away with not registering one at all.

I have also seen code which registers a new channel on each remote call. This is certainly a bad implementation. The cases where you need to register a client side channel is:

 - when you expect callbacks and you need a listening channel on which server can callback on.
 - you need to customize the channel to add properties which dont exist on the default channels. Like proxy settings for  HTTP
 - you have your own custom channel

Its also desirable to configure channels through a config file than code, so you could change channel usage without recompiling. Also make sure channels are only registered during initialization and not on each call.

As is common knowledge remoting needs server assemblies on the client for remote communication. In many cases sharing server implementation with the clients is undesirable. Interfaces can be used to acheive this isolation. An assembly which contains only interface definitions can be shared between the client and the server. A class factory pattern can be used if client needs to create instances rather than communicating with a wellknown object.

The server can define its types like this:

public class RemoteFactory : MarshalByRefObject, IRemoteFactory {

   IFoo IRemoteFactory.CreateIFooInstance()
   {
       return new Foo();
   }
}

public class Foo: MarshalByRefObject, IFoo
{
....
}

The client connects to the factory using:

// Connect to the factory
IRemoteFactory factory = (IRemoteFactory)RemotingServices.Connect
     (typeof(IRemoteFactory), "tcp://remoteHost:8080/factory.rem");
// Create IFoo instance remotely
IFoo foo = factory.CreateIFooInstance();

This essentially gives client activated style behaviour without having to share type implementation with clients. Thus, in the pseudo code above IRemoteFactory and IFoo would need to be shared between client and server, whereas RemoteFactory and Foo could be private to the server.

Same technique will work for x-domain cases when its required to keep some appdomains unpolluted by types loaded in other appdomains

There are a couple of reasons why appdomain unloads can fail. One common failure is when all threads inside the appdomain cannot be unwound. This mostly happens when there are threads running unmanaged code. In a remoting case its possible a thread that could be performing active IO at the winsock layer when the unloading is triggered. In this scenario the unload would most certainly fail. The usual workaround is to catch the unload failure and retry till the appdomain sucessfully unloads. Another workaround is to subscribe to the AppDomain.DomainUnload event and try to make sure all threads in the current appdomain are in abortable state.

In v2.0 of the framework the time the runtime will wait for all threads to be unwound is configurable through the CLR hosting APIs. An increased timeout can give a relatively better guarantee of a successful unload. Chris Brumme has some good info on appdomains in general.

You can add rejectRemoteRequests="true" on the server side tcp or http channels. With this set remoting will only allow connections from the loopback address and thus will reject cross machine calls. This is equivalent to setting bindTo="127.0.0.1" or machineName="localhost".

In v2.0 IPC channel would probably be a better choice for local machine x-process scenarios.

Most remoting users have seen one of the following exception messages during deserialization:

Because of security restrictions, the type XXX cannot be accessed
Type XXX and the types derived from it (such as {YYY}) are not permitted to be deserialized at this security level

Here is some explanation of why these security restrictions are in place for remoting:

1. Deserialization in general isn't a safe operation since it can not only load rogue types but also execute code under the server's identity. To protect against this, by default(low typefilterlevel) only "safe" types are deserializable. These include types within assemblies in the GAC with APTCA attribute (mostly system assemblies), types within private assemblies which are not strongly named.

2. The unsafe bucket of types which are explicitly disallowed are:
            System.Runtime.Remoting.ObjRef : Serialized representation of a MarshalByRefObject
            System.DelegateSerializationHolder: Serialized representation of Delegates/Events
            System.Runtime.Remoting.IEnvoyInfo: Serialized representation of Envoy Sinks
            System.Runtime.Remoting.Lifetime.ISponsor: Serialized representation of Sponsors
- ObjRef carries a URL which points to the remote object which could be spoofed
- Delegates are dangerous since they could be tweaked to call other methods with the same signature
- Envoys let you run specific code on the server end
- Sponsors are another case of spoofing related attacks.

3. As an additional level of security the thread deserializing the incoming request is only permitted to have SerializationFormatter Permission. Thus if any type constructors are accessing code requiring other permissions it would not execute.

If you are running into these exceptions the obvious fix offcourse is to change TypeFilterLevel to Full to remove these security restrictions, but before doing so it is important to guage whether it might open any security venurabilities within your server application.

This feature has been added is included in v1.0 sp3 and v1.1 versions of the framework.

My post from last week talked about OneWay messages in remoting. I should have clarified that the async and one way behaviour occurs only when invoking a method marked with [OneWay] on a remoting proxy. Invoking the same method on a regular object will not have the desired effect. It will be called synchronously like any other method.

There is a common misconception that using remoting leads to memory leaks. The fact is that the problems mostly lie in the server design more that in the use of remoting. There are two issues which often lead to server side leaks:

1. It could be related to [STAThread]. This attribute should never be used for a server side application. See my earlier post on why this could lead to leaks.

2. Issues related to lifetime management. If a server object has a infinite lifetime naturally these objects would never be collected and cause leaks. There are cases when infinite lease is necessary but in most cases these should be avoided. When an application profile shows only a few types of objects(inheriting from MarshalByRefObject) being leaked in a remoting scenario, first thing to look for is to see how the lease on these objects is being managed. Since there is no ref counting in remoting clients holding on to server resources is not an issue. All problems lie in how the server is managing its own lifetime. More about leases and lifetime can be found here.

If the app is running into a problem where the GC is not able to handle garbage at a decent pace it might be worthwhile to try if using the server gc helps its cause in any way. In general its probably anyway advisable to run the server process with server gc enabled anyway. An unmanaged host might be required to get this behaviour, but writing one should be trivial.

RemotingServices.Marshal allows you to publish an existing instance remotely. Both for server activated (wellknown) and client activated objects remoting controls when the object is instantiated and initialized. Using Marshal allows you to initialize the object before making it available remotely. The published object will still follow the same lifetime rules, meaning it will be disconnected when the lease on it expires.

Do disconnect an object published to remoting use RemotingServices.Disconnect (not RemotingServices.Unmarshal). Unmarshal is mostly a client side function to create a transparent proxy from an ObjRef.

Remoting provides a way for fire-and-forget OneWay messages from client to the server. Just adding a [OneWay] attribute to a method of your remoted type would make the method invokation oneway. Something like:

public class Remote : MarshalByRefObject
{
  public void RemoteMethod ()
  {}

  [OneWay]
  public void RemoteOneWayMethod()
  {}
}

When invoking a oneway method the client will not wait for a response and the call will return immediately. In essence the call gets converted to an async call and the client doesnt wait for a server response.

Note: This behaviour occurs only when invoking a method marked with [OneWay] on a remoting proxy. Invoking the same method on a regular object will not have the desired effect. It will be called synchronously like any other method.

One issue with NLB and remoting is the fact that remoting clients cache sockets connections for performance reasons. The side effect of this is that in the NLB case subsequent calls from the same client go to the same server introducing server affinity. But separate clients should still work with NLB and should be routed to different servers. As would be expected only SingleCall and stateless Singleton objects are supported. CAO case will fail with NLB since it requires server affinity to maintain state.

In v2.0 the TCP client-side socket cache is more flexible such that the cache timeout is configurable for more control in the load balancing case. So if per call load balancing is desired the timeout can be set to 0 meaning that each call will open a new socket.

Events and Delegates are supported in remoting. So x-appdomain and x-process delegates and eventing does work. The guidance is to not use them in cases where channels could be unreliable. In case where channels are unreliable (mostly the network in x-machine cases) its difficult to handle exceptions when events are being fired ( An unhandled exception handler might be able to handle these though). They also could lead to scalability issues when multiple events are being fired in short durations. A better design is to have a pull style pattern, than the push patterns like events. Clients can query the server rather than server calling back to clients.

That said, for x-appdomain case events / delegates should work as expected though and the new IPC channel in v2.0 could also be suitable when using these. But please use caution while using events over remoting in your application design.

 
Page view tracker