Remoting和丢失频道接收器

red*_*man 6 .net remoting appdomain

我遇到了一个远程异常:

"此远程处理代理没有通道接收器,这意味着服务器没有正在侦听的注册服务器通道,或者此应用程序没有合适的客户端通道与服务器通信."

我找到的博客文章最好地解释了原因:

第二种情况更加模糊.这发生在客户端调用服务器,服务器返回对象引用,然后客户端对服务器上引用的对象进行调用的情况.如果引用的对象位于服务器上的辅助AppDomain中,则可能抛出上述异常.如果出现问题,那是因为频道注册仅适用于调用RegisterChannel且未在辅助AppDomain中注册的频道的AppDomain.返回到客户端的对象引用指向辅助AppDomain中的对象,而不是指向主AppDomain中的代理,因此客户端和辅助AppDomain之间没有通道,调用可以通过该通道.解决方案:在引用对象所在的辅助AppDomain中注册通道.

这确实适合我的场景,因为我有一个服务将插件加载到单独的appdomains中.对象实例(在所有程序集引用的程序集中定义的接口的实现)在辅助应用程序域中创建并由服务引用(跨应用程序域,因此服务具有代理引用).然后,该服务将这些代理引用返回给应用程序.应用程序和服务之间存在已注册的通道,但插件和应用程序之间没有任何通道.

我认为代理就足以跨越appdomain边界.我真的必须在插件和应用程序之间创建通道吗?这似乎不对,所以我必须遗漏一些东西.

ant*_*duh 5

扩展@RonCohen的回答 -

在服务器上,通常会以有趣的方式创建一个完整的频道(特别是如果您想修复 TypeLevelFilter 问题 ala /sf/answers/648775641/):

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 );
Run Code Online (Sandbox Code Playgroud)

假设您在客户端使用赞助商。如果不这样做,并且客户端有一段时间没有调用远程对象,服务器将删除该对象:

Object '/70c96e17_02a8_4e1a_a040_7b671b4a66b4/3fssua+asfozgeqqkrjql+4k_1.rem' has been disconnected or does not exist at the server.
Run Code Online (Sandbox Code Playgroud)

因此,您正在使用赞助商,然后服务器偶尔会调用它来更新远程对象。但!现在服务器有一个远程对象 - 当发起人调用时,发起人被远程连接到服务器端ILease.Register。但是如果服务器没有到客户端的远程处理通道,这将失败。

因此,与服务器必须向客户端公开远程通道以供客户端访问远程对象一样,客户端必须向服务器公开远程通道,以便服务器能够访问远程对象(如赞助商)。最后,我的客户端和服务器端都具有相同的通道构建代码​​(上图),除了我在每一端使用不同的端口号。


Ron*_*hen 2

为了在从 MarshalByRefObject 派生的对象上跨应用程序域使用远程处理,有必要在两端创建通道。因此,您必须在每个应用程序域中创建通道。有有效的通道可以在同一台机器上本地执行此操作,例如 IPC 通道(使用命名管道)。

如果通信是“单向”的,即只有一侧调用代理上的方法,则您可以在此处注册一个客户端通道,并在创建对象的一侧注册服务器通道。

如果您需要双向使用,例如将日志记录对象传递给“服务器”以便接收连续的日志反馈,则必须在两端注册一个服务器通道,因为客户端突然也提供对象服务:

class MyLogger : MarshalByRefObject
{
    public Log(string text) { ... }
}

MyLogger logger = new MyLogger();
proxyObj.LongRunningCommand(logger);
Run Code Online (Sandbox Code Playgroud)