远程续约有时会失败

时间:2018-09-07 22:59:44

标签: .net appdomain remoting

我有一个用C#.NET编写的Windows桌面应用程序,该应用程序需要编译和运行部分受信任的代码。我像一个插件一样处理:将代码编译为.DLL,然后加载程序集并在AppDomain中执行。 AppDomain受到严格限制,仅具有“执行”,“基础结构”和“ RemotingConfiguration”权限,并且具有从DLL所在目录中读取文件的功能。

在调试器中运行时(Visual Studio Community 2017),远程端有时无法续订其租约。然后,对远程“插件管理器”对象进行GC处理,并且主应用程序下一次与插件交互的尝试失败,并显示RemotingException

该行为非常不一致。在大多数情况下,一切正常,但是在某些情况下,它会失败。它通常在首次续约之前就失败了,但有时在几次续约后就失败了。我现在唯一的线索是打印到调试器控制台的消息:

Exception thrown: 'System.Runtime.Remoting.RemotingException' in mscorlib.dll
Exception thrown: 'System.Runtime.Remoting.RemotingException' in mscorlib.dll

出现这些消息后的某个时间,“插件管理器”对象被GC(我添加了一个析构函数,该析构函数将消息写入控制台)。因此,似乎遥控器尝试续订租约失败,并且正在收集对象。

为什么会这样?我该怎么做才能防止这种情况?

我在发起人对象中有日志消息,显示主应用程序续订租约。他们看起来像这样:

15:17:20|Lease renewal for PluginCommon.PluginManager, last renewed 00:05:00.1248814 sec ago; renewing for 00:02:00 (host id=1)
15:19:20|Lease renewal for PluginCommon.PluginManager, last renewed 00:02:00.0281627 sec ago; renewing for 00:02:00 (host id=1)

这是我的应用空闲时的预期行为-最初5分钟,每2分钟更新一次。最初的5分钟延迟使调试工作有些沮丧。

请注意,如果没有允许安全性,我将无法覆盖InitializeLifetimeService(),因此,我不能仅仅使对象永久存在(这在这里是可以接受的解决方案)。我已经尝试了一些具有允许的安全性和10秒超时的实验,但是还没有看到它失败(鉴于失败的偶发性,这不一定意味着什么)。

我的赞助商课程符合您的期望:

class Sponsor<T> : MarshalByRefObject, ISponsor, IDisposable where T : MarshalByRefObject

“插件” AppDomain的创建如下:

        PluginManager pm = (PluginManager)mAppDomain.CreateInstanceAndUnwrap(
            typeof(PluginManager).Assembly.FullName,
            typeof(PluginManager).FullName);

        // Wrap it so it doesn't disappear on us.
        mPluginManager = new Sponsor<PluginManager>(pm);

赞助的PluginManager对象是主AppDomain与插件AppDomain之间的唯一链接。


在键入此内容时,该应用崩溃了,没有创建租约。我已经将RemotingException添加到异常中断列表中,从而产生了此堆栈跟踪:

mscorlib.dll!System.Runtime.Remoting.Channels.ChannelServices.CheckDisconnectedOrCreateWellKnownObject(System.Runtime.Remoting.Messaging.IMessage msg)  Unknown
mscorlib.dll!System.Runtime.Remoting.Channels.ChannelServices.SyncDispatchMessage(System.Runtime.Remoting.Messaging.IMessage msg)   Unknown
mscorlib.dll!System.Runtime.Remoting.Channels.CrossAppDomainSink.DoDispatch(byte[] reqStmBuff, System.Runtime.Remoting.Messaging.SmuggledMethodCallMessage smuggledMcm, out System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage smuggledMrm)  Unknown
mscorlib.dll!System.Runtime.Remoting.Channels.CrossAppDomainSink.DoTransitionDispatchCallback(object[] args)    Unknown
mscorlib.dll!System.Threading.Thread.CompleteCrossContextCallback(System.Threading.InternalCrossContextDelegate ftnToCall, object[] args)   Unknown
[AppDomain (Plugin Domain, #2) -> AppDomain (SourceGen.exe, #1)]    
mscorlib.dll!System.Runtime.Remoting.Channels.CrossAppDomainSink.DoTransitionDispatch(byte[] reqStmBuff, System.Runtime.Remoting.Messaging.SmuggledMethodCallMessage smuggledMcm, out System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage smuggledMrm)    Unknown
mscorlib.dll!System.Runtime.Remoting.Channels.CrossAppDomainSink.SyncProcessMessage(System.Runtime.Remoting.Messaging.IMessage reqMsg)  Unknown
mscorlib.dll!System.Runtime.Remoting.Channels.ADAsyncWorkItem.FinishAsyncWork(object stateIgnored)  Unknown
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(object state)  Unknown
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx)   Unknown
mscorlib.dll!System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()  Unknown
mscorlib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch()    Unknown
mscorlib.dll!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback() Unknown
[Native to Managed Transition]  

我不确定可用的解决方法是什么-也许每60秒进行一次System.Timers.Timer ping操作,即使插件域无法联系主应用程序也能使事情继续存在吗?

SO上也有类似的问题(例如this),但它们描述了一致的可再现行为。

更新:FWIW,60秒的ping kluge似乎可以正常工作。通话续订机制可以使对象保持预热状态,因此它无需请求续约。

0 个答案:

没有答案