.net – Remoting and missing channel sinks


I ran into a remoting exception:

"This remoting proxy has no channel sink which means either the server has no registered server channels that are listening, or this application has no suitable client channel to talk to the server."

The cause is best explained by this blog entry I found:

The second case is more obscure. This
occurs where the client makes a call
to the server, the server returns an
object reference, and the client then
makes a call on the referenced object
on the server. If the referenced
object is in a secondary AppDomain on
the server the above exception may be
thrown. If the the problem occurs it
is because channel registration only
applies to the AppDomain in which
RegisterChannel is called and no
channel has been registered in the
secondary AppDomain. The object
reference returned to the client
points to the object in the secondary
AppDomain, not to its proxy in the
primary AppDomain, and so there is no
channel between the client and the
secondary AppDomain across which the
call can pass. Solution: register a
channel in the secondary AppDomain in
which the referenced object exists.

This does fit my scenario as I have a service that loads plugins into separate appdomains. Object instances (implementations of an interface defined in an assembly referenced by all assemblies) are created in the secondary appdomains and referenced by the service (cross-appdomain, so the service has proxy references). The service then returns these proxy references to an application. There are registered channels between the application and the service, but nothing between the plugin and the application.

I thought that a proxy would be enough to cross the appdomain boundaries. Do I really have to create channels between the plugins and the application? That doesn't seem right at all, so I must be missing something.

Best Solution

To expand on @RonCohen's answer -

On the server, one typically creates a full channel the fun way (especially if you want to fix the TypeLevelFilter problem ala https://stackoverflow.com/a/9268223/344638):

BinaryServerFormatterSinkProvider serverProvider;
BinaryClientFormatterSinkProvider clientProvider;
Hashtable properties = new Hashtable();

serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = TypeFilterLevel.Full;

clientProvider = new BinaryClientFormatterSinkProvider();

properties.Add( "port", 8080 );

this.chan = new TcpChannel( properties, clientProvider, serverProvider );

ChannelServices.RegisterChannel( this.chan, true );

Lets say you're using a sponsor on the client side. If you don't, and the client doesn't call the remoted object for a while, the server will drop the object:

Object '/70c96e17_02a8_4e1a_a040_7b671b4a66b4/3fssua+asfozgeqqkrjql+4k_1.rem' has been disconnected or does not exist at the server.

So you're using a sponsor, which the server then occasionally calls to renew the remoted object. But! Now the server has a remoted object - the sponsor gets remoted to the server side when the sponsor calls ILease.Register. But if the server doesn't have a remoting channel to the client, this fails.

So, in the same way that the server has to expose a remoting channel to the client for the client to access remoted objects, the client has to expose a remoting channel to the server for the server to be able to access remoted objects like sponsors. In the end, both my client and server side end up having the same channel construction code (above), except I use different port numbers on each side.