我有一个自托管的WCF应用程序,其中服务对象(每次调用,单个并发)使用在名为Clarion的平台上构建的嵌入式COM对象(在整个调用中从类引用)。 COM实例与服务对象一起创建和销毁。但是,在它们下面访问一个单例存储库,需要很长时间才能初始化(非常类似于:Startup Code for Loading COM Object for WCF Service)。所以第一次通话很长。因此,我必须在启动时调用它。
如果我在启动时没有实例化COM对象,一切都很好(除了长时间的第一次调用)。但是如果我这样做,在垃圾收集之后,当尝试访问COM时,下一个请求将因访问冲突异常而崩溃。
服务对象实现IDisposable
,其中使用Marshal.ReleaseComObject
很好地释放所有COM对象。
启动调用还会释放COM对象。
我的猜测是,启动COM以某种方式被重用或回收。我不想要它!我可以确定它会永远消亡吗?或者,如果不可能,我可以将其标记为垃圾收集吗?显然,GC.KeepAlive
在这里是无关紧要的,因为这些是不同方法中的不同线程。
更多细节:最近COM对象已成为MTA。它们是线程安全的并且完全并发,但之前,当它们只是STA时,没有这样的问题。此外,当这些人在不同的线程中运行时,WCF之外没有任何不好的事情发生。
答案 0 :(得分:1)
行。看起来我就是这样。
它是血腥的隐藏单例对象,或者是COM编写的平台的运行时库(SoftVelocity Clarion)。当启动COM被杀死时,由于某种原因它被解除分配,可能是因为引用计数下降并且是时候卸载DLL本身了。虽然当我调整DllCanUnloadNow
时,它没有帮助,但我会弄清楚它来自哪里。
编辑:Clarion对COM对象的支持并不简单。由模板生成的代码执行数据库字典(分别为DctInit
和DctKill
)和主程序中某些特定类的分配和释放,这些类在主线程结束时结束。但是,在MTA COM对象主线程结束时并不意味着程序结束。因此,最简单的解决方案是嵌入代码以防止执行DctKill
。
另外,不要忘记在.Destruct方法中调用AttachThreadToClarion(TRUE)
,因为垃圾收集线程会有所不同。
此问题可能出现在老一代IDE中,其中广泛使用运行时或全局对象。谨防。