This is a discussion on AppDomains and COM objects creating/calling into managed objects - DOTNET ; Apologies for the length of this problem statement but it is a bit complicated and I just wanted to be as thorough as possible. Also, code samples are irrelevant in this case because the application is complex and pasting code ...
Apologies for the length of this problem statement but it is a bit
complicated and I just wanted to be as thorough as possible. Also,
code samples are irrelevant in this case because the application is
complex and pasting code from it would take the focus away from the
real problem. Besides, I already know that the code is (theoretically)
correct so it's all in English rather than C#.
I wonder if anyone has come across this problem. I have a .NET
container (runs as a Windows service) which creates a .NET object that
creates a legacy COM object at runtime. The COM object is a complex
one and is effectively an application on its own so it creates a whole
bunch of other COM (and some .NET) objects at different stages during
its initialisation. Because I want to be able to free up resources
after the method call finishes, I create the .NET object in a separate
AppDomain to be unloaded when I'm finished with it. However, there is
a known issue with this and as soon as you get a reference to the
object created in the new AppDomain back into your default AppDomain
for the process, it loads all the assemblies created in the secondary
domain into your default domain. So now even unloading the secondary
app domain won't free up the resources. ReleaseComObject can't be used
for reasons too complicated to explain here and too specific to the
way the legacy system is implemented. I googled it and found that
people work around this problem by creating a new .NET assembly and
deriving the entry class from MarshalByRefObject. Then introduce a
sort of indirection by creating another app domain. Now the calling
assembly creates this "intermediary" object (derived from
MarshalByRefObject) in a new app domain, which creates the target
object using reflection in yet another app domain. According to a few
articles on the internet, now unloading the secondary app domain
should return the memory to the application and I am assuming this
would be the case.
The problem however is that the COM object I create in my "inner-most"
app domain creates an object and calls into a managed C# assembly at
some stage, at which point it appears that the current thread
transitions back into the default app domain, loading all the
assemblies (circa 70) from my secondary app domain into it. The
debugger shows an "App Domain transition" line in the callstack when I
create and move into the secondary domain (which is fine and as
intended) but it doesn't indicate when I move back into the primary
domain (which is NOT the intention). However I know for sure that the
thread has transitioned back because I output AppDomain.FriendlyName
to the immediate window. This transition back to the primary app
domain undermines the whole purpose of creating objects in separate
app domains. I have found on google that a couple of people have seen
vaguely similar problems but no solutions have been posted.
I can move the .NET object creation out of the legacy COM component by
hiding the .NET object's constructor, applying the factory pattern and
then calling the factory method from the COM component to create the
target managed object. I have verified that this works and the CLR
manages to create the .NET object in the correct app domain when done
this way. Unfortunately, this solution is not ideal and not applicable
everywhere throughout my system.
Surprisingly, Richter's "CLR via C# 2.0" doesn't address any of these
issues, so has anyone got any ideas?