Question

I'm getting an exception

Cannot access a disposed object.

I know I'm getting this exception because the object has already been disposed before it had the chance to return the results. What I would like to know is whats the correct way to retrieve the objects. I may have unnecessary steps in my code and may be doing this all wrong?

I have a button click event in my main class. It calls the method shown in the code below. The GetADComputer method is located in another class called ActiveDirectory.cs. I'm getting my exception when attempting to access the results of the disposed object.

public static PrincipalSearchResult<Principal> GetADComputer(string pcName)
{
    using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
    {
        using (ComputerPrincipal computer = new ComputerPrincipal(ctx))
        {
            computer.Name = String.Format("*{0}*", pcName);

            using (PrincipalSearcher searcher = new PrincipalSearcher())
            {
                searcher.QueryFilter = computer;
                return searcher.FindAll();
            }
        }
    }            
}    
Was it helpful?

Solution

The problem is DirectoryServices uses Lazy Loading for it's information, so because you closed the context you can't retrieve the information from the Principal anymore.

You have two options, either pass the PrincipalContext in to the query so it does not go out of scope when you return:

public static DoSomthing()
{
    using(var ctx = new PrincipalContext(ContextType.Domain))
    using(PrincipalSearchResult<Principal> result = GetADComputer("some Name", ctx))
    {
        //do something with the result here.
    }
}

public static PrincipalSearchResult<Principal> GetADComputer(string pcName, PrincipalContext ctx)
{
    using (var computer = new ComputerPrincipal(ctx))
    {
        computer.Name = String.Format("*{0}*", pcName);

        using (var searcher = new PrincipalSearcher())
        {
            searcher.QueryFilter = computer;
            return searcher.FindAll();
        }
    }
} 

Or you will need to convert the results in to something that does not rely on lazy loading so you can close the connection to the directory server.

public static List<ComputerInfo> GetADComputer(string pcName, PrincipalContext ctx)
{
    using (var computer = new ComputerPrincipal(ctx))
    {
        computer.Name = String.Format("*{0}*", pcName);

        using (var searcher = new PrincipalSearcher())
        {
            searcher.QueryFilter = computer;
            using (PrincipalSearchResult<Principal> result = searcher.FindAll())
            {
                return result.Select(p=> new ComputerInfo(p.Name, p.SID)).ToList();
            }
        }
    }
} 

public class ComputerInfo
{
    public ComputerInfo(string name, SecurityIdentifier sid)
    {
        Name = name;
        SID = sid;
    }

    public string Name {get; set;}
    public SecurityIdentifier SID {get; set;}
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top