Why is this object being modified when used?

I am trying to get a list of AD users with DirectorySearcher:

using (var entry = new DirectoryEntry("LDAP://mydomain.com"))
using (var search = new DirectorySearcher(entry))
{
    // Setup the query...
    search.PageSize = 1000;

    using (SearchResultCollection results = search.FindAll())
    {
        foreach (SearchResult result in results)
        {
            // Read the results and insert in a list
        }
    }
}

This request can take up to a minute, so I start in a thread from a thread pool ( ThreadPool.QueueUserWorkItem). The query works fine and I get the correct results.

However, if I close the application at run-time of the request, I regularly get this the MDA: RaceOnRCWCleanup was detected. In fact, my thread is still running and waiting for the enumeration to continue:

[Managed to Native Transition]
System.DirectoryServices.dll!System.DirectoryServices.SearchResultCollection.ResultsEnumerator.MoveNext() + 0x4a bytes
MyApp.exe!MyApp.ActiveDirectory.FetchAllUsers() Line 125 + 0x4dd bytes

At the same time, the finalizer thread terminates the instance DirectoryEntry:

mscorlib.dll!System.__ComObject.ReleaseSelf() + 0x5 bytes   
mscorlib.dll!System.Runtime.InteropServices.Marshal.ReleaseComObject(object o) + 0x84 bytes 
System.DirectoryServices.dll!System.DirectoryServices.DirectoryEntry.Unbind() + 0x27 bytes  
System.DirectoryServices.dll!System.DirectoryServices.DirectoryEntry.Dispose(bool disposing) + 0x29 bytes   
System.dll!System.ComponentModel.Component.Finalize() + 0x1b bytes

I can verify (through Make Object IDin Visual Studio) that finalization DirectoryEntryis the internal instance used SearchResultCollection.

  • Why DirectoryEntrydoes this terminate when used yet?
  • , , , , , ?
  • - ? .

1

GC.KeepAlive(results) foreach. GC.KeepAlive() DirectoryEntry results, . : ...

using (var entry = new DirectoryEntry("LDAP://mydomain.com"))
using (var search = new DirectorySearcher(entry))
{
    using (SearchResultCollection results = search.FindAll())
    {
        var rootEntryField = typeof(SearchResultCollection).GetField("rootEntry", BindingFlags.NonPublic | BindingFlags.Instance);
        var rootEntry = rootEntryField.GetValue(results);

        foreach (SearchResult result in results) // Callstack is here when entry is finalized
        {
            // Do something
        }

        GC.KeepAlive(results);
        GC.KeepAlive(rootEntry); // This is the entry being finalized
   }

   GC.KeepAlive(search);
   GC.KeepAlive(entry);
}

, , , SearchResultCollection , MDA. , , , , Dispose(). , GC , , ...

2

, , GC / , , , -, . , :

using (new MyFinalizableType())
{
    System.Threading.Thread.Sleep(100000);
}

, , , , ~MyFinalizableType() , ( Threads).

, , GC , , RaceOnRCWCleanup MDA.

, GC.SuppressFinalize , COM , Dispose() . AFAIK COM , / .

+4
2

, DirectoryEntry . , -.

, - COM-wrap interop, .. , , GC.

, GC.KeepAlive(entry); foreach. , , entry, ( JIT , ).

0

, . , , . , , , this ( ) , . (, , , .)

, / , .

- .

0
source

All Articles