سؤال

I have a self-hosted WCF application where the service objects (per call, single concurrency) use embedded COM objects (referenced from the class throughout the call) built on a platform called Clarion. The COM instances are created and destroyed together with the service objects. However, underneath they access a singleton repository which takes long time to initialise (very similar to this: Startup Code for Loading COM Object for WCF Service). So a first call is very long. Hence, I must call it on startup.

If I don't instantiate the COM object on startup, everything is fine (except for the long first call). But if I do, after the garbage collection the next request will crash with access violation exception when trying to access the COM.

The service objects implement IDisposable where all the COM objects are nicely released using Marshal.ReleaseComObject. The startup call also releases the COM object.

My guess is that the startup COM gets somehow reused or recycled. I don't want it to! Can I make sure it dies forever? Or if it's not possible, can I mark it not for garbage collection? Obviously, GC.KeepAlive is irrelevant here, because these are different threads in different methods.

More details: the COM objects were made MTA-capable recently. They are thread-safe and fully concurrent, but before, when they were STA only, there was no such issue. Also, nothing bad happens outside of WCF when these guys run in separate threads.

هل كانت مفيدة؟

المحلول

OK. Looks like I'm on it.

It's the bloody hidden singleton objects or, rather, a runtime library of the platform the COM is written on (SoftVelocity Clarion). It got deallocated for some reason when the startup COM got killed, probably because the reference count went down and it was time to unload the DLL itself. Although when I tweaked DllCanUnloadNow, it did not help, but I'll figure out where it's coming from.

EDIT: Clarion support of COM objects is not straightforward. The code, generated by templates, performs allocation and deallocation of the database dictionary (DctInit and DctKill respectively) and some specific classes in the main program, which ends when the main thread ends. However, in MTA COM objects end of the main thread does not mean end of the program. Hence, the easiest solution is to embed code to prevent execution of DctKill.

Also, do not forget to call AttachThreadToClarion(TRUE) in .Destruct methods, since the garbage collection thread will be different.

This issue may surface in older generation IDEs where a runtime or global objects are used extensively. Beware.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top