COM-object was released unintendedly - c#

I have a helper-class for my unit-tests that share a reference to an COM-object in memory:
public class UnitTestGeometryProvider
{
public static readonly IGeometry Geometry = Deserialize();
}
The geometry is deserialized from a Xml file which is stored as a resource file and appended to the project. Afterwards it is wrapped into a COM object:
public static IGeometry Deserialize()
{
return (IGeometry) new XMLSerializerClass().LoadFromString(myXDoc.OuterXml, null, null);
}
Now I have two test-methods that use the geometry stored within this class:
[TestClass()]
public class MyTest
{
[TestMethod()]
public void FirstTest()
{
var p = UnitTestGeometryProvider.Geometry;
}
[TestMethod()]
public void SecondTest()
{
var p = UnitTestGeometryProvider.Geometry;
}
}
When running the second one I get a COMException:
COM object that has been separated from its underlying RCW cannot be used
I wonder why the reference to the COM-object is released as it is marked static in UnitTestGeometryProvider and I do not explicitly release it. So even if the managed resource to the instance would go out of scope (which is does not at it is static), the underlying COM object should go away only when all my tests finished or more general when the application terminates, or do I miss anything?
I am using ArcObjects and Visual NUnit.

Due to the comments by Hans Passant I found the actual problem.
Obviously the Visual-NUnit-Framework decides to create a separate thread for every test. Thus whenever I create a COM-object - be it static or not - this object lives on this single thread and cannot be used in another one. If the thread dies also does the COM-object or to be more precise the reference to it. This leads to the GC kicking in throwing the COM-object away as no more managed references to it exist within that thread.
The solution is pretty straitforward: I changed the static field to instance-members and created an instance-member of type UnitTestGeometryProvider within my test-class. Thus a new provider is generated by every test.
However this solution is quite annoying because the Geometry-property has to be initialized and therefor the Deserialize-method runs for every test instead of only once for all tests.
I donĀ“t know if there is a thread-safe solution to not kill the reference to the COM-object when the first thread that intialized it dies.

Related

Why does instantiating XmlSerializer before ServiceHost.Open is called produce a memory & handle leak

When looking for a memory- and handleleak in a .NET/WCF/Windows Service I noticed strange behavior that I cannot explain.
Here the setup and the resolution. What I am looking for would be an explanation for the observed behavior.
I installed a Windows Service.
I started the service.
I called a simple method with a transactional WCF call (new channel per call - no caching).
For each call about 2 handles remain in memory.
This can be observed if the following items are applicable:
It is a Windows Service; don't run it as a Console App.
Use a Transaction (separate process or machine tested only) to call the WCF method.
Before calling ServiceBase.Run(servicesToRun); instantiate XmlSerializer with some type.
The type is a custom type. It does not occur with new XmlSerializer(typeof(string)) or new XmlSerializer(typeof(XmlDocument)). No call to serialize is necessary. It is enough if the custom type has only a string as property (no handles anywhere!)
Creating a static XmlSerialization.dll using i.e. SGen.exe will not produce this problem.
My Code already includes the fix:
Use XmlSerializer earliest in OnStart():
Program.cs
WindowsService winSvc = new WindowsService();
ServiceBase[] servicesToRun = new ServiceBase[]{winSvc};
ServiceBase.Run(servicesToRun);
WindowsService.cs
internal sealed class WindowsService : ServiceBase
{
private ServiceHost wcfServiceHost = null;
internal WindowsService()
{
AutoLog = true;
CanStop = true;
CanShutdown = true;
CanPauseAndContinue = false;
}
internal void StartWcfService()
{
wcfServiceHost = new ServiceHost(typeof(DemoService));
wcfServiceHost.Open();
}
protected override void Dispose(bool disposing)
{
if (wcfServiceHost != null)
{
wcfServiceHost.Close();
}
base.Dispose(disposing);
}
protected override void OnStart(string[] args)
{
new XmlSerializer(typeof(MyType));
StartWcfService();
}
}
DemoService.cs
[ServiceBehavior
(
InstanceContextMode = InstanceContextMode.PerSession,
TransactionAutoCompleteOnSessionClose = false,
IncludeExceptionDetailInFaults = true
)
]
public sealed class DemoService : IDemoService
{
[TransactionFlow(TransactionFlowOption.Allowed)]
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public int Add(int a, int b)
{
return a + b;
}
}
Client.cs:
IChannelFactory<IDemoService> channelFactory = new ChannelFactory<IDemoService>("defaultClientConfiguration");
IDisposable channel = null;
for (int index = 0; index < 5000; index++)
{
using
(
channel = (IDisposable)channelFactory.CreateChannel(new EndpointAddress("net.tcp://localhost:23456/DemoService")))
{
IDemoService demoService = (IDemoService)channel;
using (TransactionScope tx = new TransactionScope(TransactionScopeOption.RequiresNew))
{
demoService.Add(3, 9);
tx.Complete();
}
)
}
Can someone explain this behavior?
Please note, I'm not interested in finding a way to avoid the leak (I already know how to do this) but in an explanation (i.e. WHY is it happening).
I think some of the inner workings do this question justice. I do this from the back of my head, since I ran into this problem as well some time ago, and it took me a day to track back including extensive use of Reflector and ANTS Memory profiler (at my previous company)... here goes:
What the XML Serializer internally does is it creates a class (let's call it 'A') using System.Reflection.Emit that accepts the type you pass to it. Constructing such a class costs a lot of time relatively speaking, and are reusable since types don't change. Because of this, the constructed types are stored in a dictionary, e.g. it ends up with some Dictionary .
For known (basic) types, the serializer code is fixed, e.g. the serialization of a string is not going to change no matter how many times you restart your application. Note the difference with 'A' where any type that's unknown to the serialization factory till it's first passed to the XMLSerializer.
The first time the type is used by the XMLSerializer, this process takes place for both the type you pass and all types it needs (e.g. all fields and properties that require serialization).
About the leak... When you call the ChannelFactory, it constructs serializer if it doesn't exist yet. For that it checks if the serializer already exists in the Dictionary and if not, creates one by making an instance of ISomeSerializerType.
For some stupid reason, there is a bug in the factory that constructs a new serializer without storing it in the dictionary. Once constructed, you end up with a new type - which shows up as a leak (remember: types can never be unloaded) - even though the objects are correctly disposed. When you use XMLSerializer first or create a static class, it correctly uses the Dictionary cache, which means it won't leak. So there you have it, it is a bug. I used to have access to ANTS Memory Profiler, which showed this quite nicely.
Hope this explains.
The XmlSerializer documentation says this:
To increase performance, the XML serialization infrastructure dynamically generates assemblies to serialize and deserialize specified types. The infrastructure finds and reuses those assemblies. This behavior occurs only when using the following constructors:
XmlSerializer.XmlSerializer(Type)
XmlSerializer.XmlSerializer(Type, String)
If you use any of the other constructors, multiple versions of the same assembly are generated and never unloaded, which results in a memory leak and poor performance. The easiest solution is to use one of the previously mentioned two constructors. Otherwise, you must cache the assemblies in a Hashtable, as shown in the following example.
http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx

C# Reflection: Replace a referenced assembly

I am currently writing a framework for MutationTesting. The code is almost complete, but there is a tiny bit which (after spending half a day on it) I cannot figure out:
via reflection I would like to execute a method "TestMethod" which is inside the class "TestClass". The project in which "TestClass" is, references an essembly, lets call it "Proband.dll".
The "TestMethod" creates an object of some type inside the Proband.dll and executes a method on that object.
In order to clarify a little:
TestClass - is a class that contains unit tests.
TestMethod - is a single unit test.
Proband.dll - contains the method/class to test.
Before executing the TestMethod, I already successfully disassembled, mutated and reassembled the Proband.dll. So now I have a new "Proband.dll" which shall be taken by the TestClass instead!
The problem is that the TestClass is already in the middle of execution. I was thinking whether it is possible to create an AppDomain in which the new Proband.dll will be loaded and inside the fresh AppDomain, the TestMethod will be executed.
I have already created this AppDomain and successfully loaded the new Proband.dll into it, however, I do not know how to execute the TestMethod inside this new AppDomain. Also I do not know whether this is going to "replace" the old Proband.dll for the test method.
Here is my TestClass:
[TestClass()]
public class TestClass
{
[TestInitialize()]
public void MyTestInitialize()
{
// code to perform the mutation.
// From here, the "TestMethod" should be called with
// the new "Proband.dll".
}
[TestMethod()]
public void TestMethod()
{
// test code calling into Proband.dll
}
}
Does anyone have an idea of how this could be achieved? Or any clue or keyword?
Thanks,
Christian
This is probably overkill, but check out my answer:
Static Fields in AppDomain
You'll want to create the TestClass in the AppDomain that you've loaded the Proband.dll in, and use a MarshalByRef to keep the class in the AppDomain (so you can unload it later).
Here is more about what I did (not exact, as i'm changing it to match more what you need).
// Create Domain
_RemoteDomain = AppDomain.CreateDomain(_RemoteDomainName,
AppDomain.CurrentDomain.Evidence,
AppDomain.CurrentDomain.BaseDirectory,
AppDomain.CurrentDomain.BaseDirectory,
true);
// Load an Assembly Loader in the domain (mine was Builder)
// This loads the Builder which is in the current domain into the remote domain
_Builder = (Builder)_RemoteDomain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName, "<namespace>.Builder");
_Builder.Execute(pathToTestDll)
public class Builder : MarshalByRefObject
{
public void Execute(string pathToTestDll)
{
// I used this so the DLL could be deleted while
// the domain was still using the version that
// exists at this moment.
Assembly newAssembly = Assembly.Load(
System.IO.File.ReadAllBytes(pathToTestDll));
Type testClass = newAssembly.GetType("<namespace>.TestClass",
false, true);
if (testClass != null)
{
// Here is where you use reflection and/or an interface
// to execute your method(s).
}
}
}
This should provide you the solution you need.

.NET Remoting and HttpContext.Current

We have a plugin system where the plugin code runs on a separate AppDomain from the main process, using .NET remoting for the objects to communicate.
One class is similar to HttpContext.Current (which also suffers from the problem) (edit, the actual implementation):
public class MyClass
{
public static MyClass Instance
{
get
{
if(HttpContext.Current != null)
return HttpContext.Current.Items["MyClassInstance"];
}
set
{
if(HttpContext.Current != null)
HttpContext.Current.Items["MyClassInstance"] = value;
}
}
}
Then, we have a communicating object which inherits from MarshalByRefObject:
public class CommunicatingClass : MarshalByRefObject, ICommunicatingClass
{
public void DoSomething()
{
MyClass.Instance.DoSomething();
}
}
The CommunicatingClass is created on the main AppDomain, and works fine. Then, there's the plugin class, which is created on its AppDomain, and given an instance of the CommunicatingClass:
public class PluginClass
{
public void DoSomething(ICommunicatingClass communicatingClass)
{
communicatingClass.DoSomething();
}
}
The problem is, that even though CommunicatingClass resides on the main appdomain (verified with the Immediate Window), all of the static data such as MyClass.Instance and HttpContext.Current have disappeared and are null. I have a feeling that MyClass.Instance is somehow being retrieved from the plugin AppDomain, but am unsure how to resolve this.
I saw another question that suggested RemotingServices.Marshal, but that did not seem to help, or I used it incorrectly. Is there a way that the CommunicatingClass can access all static methods and properties like any other class in the main AppDomain?
Edit:
The PluginClass is given an instance like this:
public static PluginClass Create()
{
var appDomain = GetNewAppDomain();
var instance = (PluginClass)appDomain.CreateInstanceAndUnwrap(assembly, type);
instance.Communicator = new CommunicatingClass();
return instance;
}
Edit 2:
Might have found the source of the problem. MyClass.Instance is stored in HttpContext.Current.Items (see above edit).
Is there any way at all that HttpContext.Current can access the correct HttpContext? I'm still wondering why, even though it is being run in HttpContext.Current's AppDomain, CommunicatingClass.DoSomething, when calling MyClass.Instance, retrieves stuff from PluginClass' AppDomain (if that makes any sense).
So my co-worker and I worked this out, finally, with a bunch of help from Reflector.
The main problem is that HttpContext.Current is null when accessed via a remoting call.
The HttpContext.Current property is stored in an interesting manor. A few nested setters down, you reach CallContext.HostContext. This is a static object property on a CallContext.
When the CallContext is set, it first checks if the value is an ILogicalThreadAffinitive.
If it is, it stores the value in the current thread's LogicalCallContext.
If it's not, it stores the value in the current thread's IllogicalCallContext.
HttpContext is not an ILogicalThreadAffinitive, so it is stored in the IllogicalCallContext.
Then, there's remoting.
We didn't dig too far in to its source, but what it does was inferred from some other functions.
When a call is made to a remote object from a different AppDomain, the call is not directly proxied to the original thread, running in the exact same execution context.
First, the ExecutionContext of the original thread (the one containing HttpContext.Current) is captured, via ExecutionContext.Capture (more in this in a bit).
Then, the ExecutionContext returned from Capture is passed as the first argument to ExecutionContext.Run, esentially forming the code:
Delegate myRemoteCall; //Assigned somewhere else in remoting
ExecutionContext.Run(ExecutionContext.Capture(), x => { myRemoteCall() }, null);
Then, completely transparently, your code in the remote object is accessed.
Unfortunately, HttpContext.Current is not captured in ExecutionContext.Capture().
Here lies the essential difference between an IllogicalCallContext and a LogicalCallContext.
Capture creates a brand-new ExecutionContext, essentially copying all of the members (such as the LogicalCallContext) in to the new object. But, it does not copy the IllogicalCallContext.
So, since HttpContext is not an ILogicalThreadAffinative, it cannot be captured by ExecutionContext.Capture.
The solution?
HttpContext is not a MarshalByRefObject or [Serializable] (probably for good reason), so it cannot be passed in to the new AppDomain.
But, it can cross ExecutionContexts without problem.
So, in the main AppDomain's MarshalByRefObject which is given as a proxy to the other AppDomain, in the constructor give it the instance of HttpContext.Current.
Then, in each method call of the new object (unfortunately), run:
private HttpContext _context;
private void SyncContext()
{
if(HttpContext.Current == null)
HttpContext.Current = _context;
}
And it will be set without problem. Since HttpContext.Current is tied to the IllogicalCallContext of the ExecutionContext, it will not bleed in to any other threads that ASP.NET might create, and will be cleaned up when the copy ExecutionContext is disposed.
(I could be wrong about much of this, though. It's all speculation and reflection)
I believe you'll need to derive MyClass from MarshalByRefObject as well.

know when a new thread was created in the AppDomain your application is running after?

I would like to know if there is any way to get an event (or something else) that tells you when a new thread was created on your appdomain (C# application)? The basic idea is that when a new thread is created I need to "initialize" the thread with some settings.
I do not want to go all over my code and do that, as I don't know what future will hold.
Create a thread static variable, and initialize anything you need in the constructor.
class ThreadEnvironmentSettings
{
[ThreadStatic]
public static readonly ThreadEnvironmentSettings Settings =
new ThreadEnvironmentSettings();
public ThreadEnvironmentSettings()
{
SetupJavaEnvironment();
}
public void EnsureSetup(){
// Doesn't do anything but required to 'touch' the thread variable
}
}
Then before calling any methods that require an established environment:
ThreadEnvironmentSettigns.Settings.EnsureSetup();
I assume that java loaders execute on the other process. And .NET code just specifies correct arguments for the command line - then you can use environment variables for the whole process.
Environment variables are global to the whole process (that is all threads will have access to them even newly created ones). Here's how to set a variable in C#.

Multiple threads accessing singleton object in VS2010

I'm using Visual Studio 2010 to write a simple C#/.NET GUI app, wherein I use a Logger class to write tracing/debugging info to a single file from within all of the various classes of the project. (See source code below.)
Each class's constructor writes an entry to the log when one of its object types is instantiated. One of those classes is a custom GUI controller component (class FileAttributesCtl), which is contained in a couple of the GUI forms used by the program.
The problem I'm having is that two logfiles are created, about 200 msec apart. The first logfile contains (only) a message that a FileAttributesCtl object has been constructed, and the second contains all of the other messages written to the (supposedly) shared logfile output stream. So every time I execute my project code, I get two logfiles.
Stranger still, every time I rebuild my project (F6), a logfile is created for the FileAttributesCtl object, indicating that an control object of this type is actually instantiated during the build process.
This apparently has something to do with threading. If the logfile is not named uniquely (i.e., if I do not append a unique date/time string to the filename), I get an exception, indicating that more than one process (which is actually the VS2010 process itself) is currently using the file.
So my question is: How do I get the singleton object to actually be a single object?
A secondary question is: Why is VS2010 acting this way?
//----------------------------------------
// Logger.cs
class Logger
{
// Singleton object
private static Logger s_logger =
new Logger("C:/Temp/foo.log");
public static Logger Log
{
get { return s_logger; }
}
private TextWriter m_out;
private Logger(string fname)
{
// Add a date/time suffix to the filename
fname = ...;
// Open/create the logging output file
m_out = new StreamWriter(
new FileStream(fname, FileMode.Create, FileAccess.Write,
FileShare.Read));
m_out.WriteLine(DateTime.Now.ToString(
"'$ 'yyyy-MM-dd' 'HH:mm:ss.fff"));
}
...
}
//----------------------------------------
// FileAttributesCtl.cs
public partial class FileAttributesCtl: UserControl
{
private Logger m_log = Logger.Log;
public FileAttributesCtl()
{
m_log.WriteLine("FileAttributesCtl()"); //Written to first logfile
InitializeComponent();
}
...
}
//----------------------------------------
// FileCopyForm.cs
public partial class FileCopyForm: Form
{
private Logger m_log = Logger.Log;
public FileCopyForm()
{
// Setup
m_log.WriteLine("FileCopyForm()"); //Written to second logfile
// Initialize the GUI form
m_log.WriteLine("FileCopyGui.InitializeComponent()");
InitializeComponent();
...
}
...
}
Note: This is very similar to a question from Dec 2009:
Access to singleton object from another thread
but it does not have the answers to my question.
Update
Further investigation shows that the VS2010 is indeed instantiating the custom component during the build, probably so that it can render it in the Designer window.
Also, there are indeed two separate threads calling the Logger constructor (each having a different ManagedThreadID).
Using a static class initializer to construct the singleton object does not work; I still get two logfiles.
Resolution
Upon closer examination, I notice that the custom control is getting instantiated twice, and this is being shown in both logfiles.
Therefore I think the problem is entirely due to the fact that VS instantiates the custom control object prior to executing the program that results in the first logfile being created. The second logfile is then created after the program starts normal execution.
Thus the first logfile is simply a side effect of the build process, and does not really have anything to do with multiple threads executing during normal program operation.
The obvious solution is to remove all logfile side-effect code from the component constructors. Or simply just ignore the first logfile altogether.
It could very well be that Visual Studio is building your UI component (to display in the designer) and in the process, your constructor is getting called which is why you're seeing that log file during the build process.
Static data + threads = trouble
You need to synchronize access to the singleton (and initialization of the singleton).
A static constructor may help
class Logger
{
private static Logger
static Logger()
{
s_logger = new Logger("C:/Temp/foo.log");
}
// ...
or better yet use a logging library (log4net) that handles all this stuff for you.
As for VS builds causing a log to be created, I'm not surprised. It is probably instantiating the forms to discover information about your forms via reflection.
update per comments
#LoadMaster "The static class initializer does not
work. I added more info to the logfile
output to include the current thread's
ManagedThreadID, and sure enough,
there are two different thread IDs
creating the two logfiles."
That's strange. Per MSDN
The static constructor for a class
executes at most once in a given
application domain. The execution of a
static constructor is triggered by the
first of the following events to occur
within an application domain:
An instance of the class is created.
Any of the static members of the class
are referenced.
Your thread must have moved AppDomains or there is some code missing from your snippets.

Categories

Resources