user390480
user390480

Reputation: 1665

Active Directory Search getting Object reference not set

The below code works on my local machine by returning the user's full name from Active Directory:

string principal = System.Web.HttpContext.Current.Request.LogonUserIdentity.Name.Remove(0, 12);

string filter = string.Format("(&(ObjectClass={0})(sAMAccountName={1}))", "person", principal);

string[] properties = new string[] { "fullname" };

DirectoryEntry adRoot = new DirectoryEntry("LDAP://myserver.com");
adRoot.AuthenticationType = AuthenticationTypes.Secure;

DirectorySearcher searcher = new DirectorySearcher(adRoot);

searcher.SearchScope = SearchScope.Subtree;

searcher.ReferralChasing = ReferralChasingOption.All;

searcher.PropertiesToLoad.AddRange(properties);

searcher.Filter = filter;

SearchResult result = searcher.FindOne();

DirectoryEntry directoryEntry = result.GetDirectoryEntry();

string displayName = directoryEntry.Properties["displayName"][0].ToString();

if (string.IsNullOrEmpty(displayName) == false)
{
    return displayName;
}

When I publish it to the development server I get the following error:

System.NullReferenceException: Object reference not set to an instance of an object.

The error is thrown on the following line:

DirectoryEntry directoryEntry = result.GetDirectoryEntry();

I have tried

DirectoryEntry adRoot = new DirectoryEntry("LDAP://" + domain, AdAdminUsername, AdAdminPassword, AuthenticationTypes.Secure);

but still no joy.

Any ideas?

Thanks!

Upvotes: 2

Views: 6063

Answers (2)

JPBlanc
JPBlanc

Reputation: 72680

Just from outside : your string called principal is built by the following :

string principal = System.Web.HttpContext.Current.Request.LogonUserIdentity.Name.Remove(0, 12);

Have you log 'System.Web.HttpContext.Current.Request.LogonUserIdentity.Name' on your dev server ? This static construction may be the begining of you troubles because if principal is'nt what you think it is, the result of FindOne may be NULL.

Upvotes: 1

marc_s
marc_s

Reputation: 755371

In your current code, you must check for NULL after the call to FindOne() - it could return a NULL value if no matching directory entry was found.

See the MSDN docs:

If more than one entry is found during the search, only the first entry is returned. If no entries are found to match the search criteria, a null reference (Nothing in Visual Basic) is returned.

Plus, you should also always check for the presence of a property before accessing it - it could be absent.....

Therefore, your code should be something like this:

SearchResult result = searcher.FindOne();

if(result != null)
{
    DirectoryEntry directoryEntry = result.GetDirectoryEntry();

    if(directoryEntry.Properties["displayName"] != null &&
       directoryEntry.Properties["displayName"].Length > 0)
    {
       string displayName = directoryEntry.Properties["displayName"][0].ToString();

       if (!string.IsNullOrEmpty(displayName))
       {
          return displayName;
       }
    }
}

But: if you're on .NET 3.5 or newer, you should check out the System.DirectoryServices.AccountManagement namespace which makes a lot of things a lot easier when dealing with Active Directory.

You can use a PrincipalSearcher and a "query-by-example" principal to do your searching:

// create your domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);

// define a "query-by-example" principal - here, we search for a UserPrincipal 
// and with the first name (GivenName) of "Bruce"
UserPrincipal qbeUser = new UserPrincipal(ctx);
qbeUser.SamAccountName = "whatever you're looking for.....";

// create your principal searcher passing in the QBE principal    
PrincipalSearcher srch = new PrincipalSearcher(qbeUser);

// find all matches
foreach(var found in srch.FindAll())
{
    // do whatever here - "found" is of type "Principal" - it could be user, group, computer.....          
}

If you haven't already - absolutely read the MSDN article Managing Directory Security Principals in the .NET Framework 3.5 which shows nicely how to make the best use of the new features in System.DirectoryServices.AccountManagement

Of course, depending on your need, you might want to specify other properties on that "query-by-example" user principal you create:

  • Surname (or last name)
  • DisplayName (typically: first name + space + last name)
  • SAM Account Name - your Windows/AD account name
  • User Principal Name - your "username@yourcompany.com" style name

You can specify any of the properties on the UserPrincipal and use those as "query-by-example" for your PrincipalSearcher.

Upvotes: 2

Related Questions