DirectoryServices bug?

B

bugnthecode

Hi, I'm building a small desktop app in VS Std 2005 with C# and .net
2.0. I've managed to get the code together to query the ldap my company
has, but every time I attempt to access a specific property a COM
Exception gets thrown, and I can't figure out why. This is a desktop
app.

example("ldap.example.com", "ou=People,dc=example,dc=com");

public void example(string server, string ou) {
searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + server
+ "/" + ou, "", "", AuthenticationTypes.ReadonlyServer));

searcher.Filter = "(uid=wsmith)";
SearchResultCollection results = searcher.FindAll();
Console.WriteLine((string)results[0].GetDirectoryEntry().Properties["gPhotoID"]);
// OFFENDING LINE!
}

So that's pretty much the smallest bit of code I can use and get the
error. All the other properties I've tried to access so far have worked
just fine, I've even found some properties to be a collection of values
which works just fine. The gPhotoID should contain a url to a picture
which would look like
"http://intranet.example.com/employees/pictures/18273010.JPG".

The error that I'm getting is:
System.Runtime.InteropServices.COMException was unhandled
Message="Unknown error (0x8000500c)"
Source="System.DirectoryServices"
ErrorCode=-2147463156
StackTrace:
at
System.DirectoryServices.PropertyValueCollection.PopulateList()
at
System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry
entry, String propertyName)
at
System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Entry()
at
System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Current()
at UserManager.UserFactory.Find(String criteria) in D:\My
Documents\Visual Studio
2005\Projects\UserManager\UserManager\UserFactory.cs:line 58
at UserManager.UserFactory.FindByUnix(String unix) in D:\My
Documents\Visual Studio
2005\Projects\UserManager\UserManager\UserFactory.cs:line 26
at UserManagerTest.Program.Main(String[] args) in D:\My
Documents\Visual Studio
2005\Projects\UserManagerTest\UserManagerTest\Program.cs:line 10
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[]
args)
at System.AppDomain.ExecuteAssembly(String assemblyFile,
Evidence assemblySecurity, String[] args)
at
Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object
state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

I can't seem to find a solution. I've been googling for over an hour,
and most of the answers I find pertain to credential issues, and
asp.net issues. Can someone please offer assistance?

Thanks,
Will
 
M

Marc Scheuner

example("ldap.example.com", "ou=People,dc=example,dc=com");
public void example(string server, string ou) {
searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + server
+ "/" + ou, "", "", AuthenticationTypes.ReadonlyServer));

searcher.Filter = "(uid=wsmith)";
SearchResultCollection results = searcher.FindAll();
Console.WriteLine((string)results[0].GetDirectoryEntry().Properties["gPhotoID"]);
// OFFENDING LINE!

Well, there are two problems here:

1) The "searcher.FindAll()" call could possibly return no results, if
your filter doesn't match any records - so blindly using "results[0]"
will cause an exception when no result has been returned

2) Along similar lines - even if you have one or multiple results
returned, those possibly will not contain any value in "gPhotoID"
(because the path has not been set), and then using that (by casting
it to a string) will also cause an exception.

Furthermore - if you want to access just a single property (or a few)
on the search result, your best bet is to specify those properties on
the searcher object itself and query them from the result directly
(without having to retrieve the full "DirectoryEntry" object and
access them there).

So your search should look something like this:

searcher.Filter = "(uid=wsmith)";
// specify which properties to load directly into the result
searcher.PropertiesToLoad.Add("gPhotoID");

SearchResultCollection results = searcher.FindAll();

// check to see if we have any results !
if(results.Count > 0)
{
SearchResult firstResult = results[0];

// check to see if result contains a value for the property
if(firstResult.Properties.Contains["gPhotoID"])
{
// the result's property might be a multi-value
// string property, so pick string [0] from the
// collection
string photoID =
firstResult.Properties["gPhotoID"][0].ToString();
}
}

HTH
Marc
 
B

bugnthecode

Thanks for your reply. I know that it's possible to not get any results
back from searcher.FindAll(), but I was trying to show the smallest
possible example. I have tried using the ProperitesToLoad.Add() and
when I do even the properties I don't specify are actually accessible.
Do you know why this would happen? I'll try it again specifying every
property I would like to load, and checking for multiple values for
each property. I just don't understand why that specific property
throws an exception when none of the others do. Could it be the format
that the string is in (in the format for a url?)? Would the length have
to do with it (the length of that property for myself in the directory
is 58 characters)? And what exactly does that exception mean?

Thanks for your help Marc,
Will

Marc said:
example("ldap.example.com", "ou=People,dc=example,dc=com");

public void example(string server, string ou) {
searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + server
+ "/" + ou, "", "", AuthenticationTypes.ReadonlyServer));

searcher.Filter = "(uid=wsmith)";
SearchResultCollection results = searcher.FindAll();
Console.WriteLine((string)results[0].GetDirectoryEntry().Properties["gPhotoID"]);
// OFFENDING LINE!

Well, there are two problems here:

1) The "searcher.FindAll()" call could possibly return no results, if
your filter doesn't match any records - so blindly using "results[0]"
will cause an exception when no result has been returned

2) Along similar lines - even if you have one or multiple results
returned, those possibly will not contain any value in "gPhotoID"
(because the path has not been set), and then using that (by casting
it to a string) will also cause an exception.

Furthermore - if you want to access just a single property (or a few)
on the search result, your best bet is to specify those properties on
the searcher object itself and query them from the result directly
(without having to retrieve the full "DirectoryEntry" object and
access them there).

So your search should look something like this:

searcher.Filter = "(uid=wsmith)";
// specify which properties to load directly into the result
searcher.PropertiesToLoad.Add("gPhotoID");

SearchResultCollection results = searcher.FindAll();

// check to see if we have any results !
if(results.Count > 0)
{
SearchResult firstResult = results[0];

// check to see if result contains a value for the property
if(firstResult.Properties.Contains["gPhotoID"])
{
// the result's property might be a multi-value
// string property, so pick string [0] from the
// collection
string photoID =
firstResult.Properties["gPhotoID"][0].ToString();
}
}

HTH
Marc
 
B

bugnthecode

Ok so I tried it again with specifying each property before performing
the search, and checking for multiple results as specified before. I
still get the same exception. I've tried accessing other properties
that are available, but I don't need and I can seem to access those
just fine, but every time I get to this one it throws an exception. Any
Ideas??

Thanks,
Will
 
M

Marc Scheuner

Ok so I tried it again with specifying each property before performing
the search, and checking for multiple results as specified before. I
still get the same exception. I've tried accessing other properties
that are available, but I don't need and I can seem to access those
just fine, but every time I get to this one it throws an exception. Any
Ideas??

Are you still using the ".GetDirectoryEntry()" call?? This will return
the complete DirectoryEntry for the search result - that will
obviuosly have all the properties available !

Marc
 
S

ssg31415926

Have you seen this posting: "Errors Reading IBM ITIM LDAP properties"
in microsoft.public.adsi.general ? It doesn't exactly apply to your
situation as it's about non-AD LDAP directories but maybe gPhoto­ID is
as poorly handled by the ADSi-.NET conversion as non-AD attributes?

SSG
 
W

wayne_bradney

bugnthecode said:
Hi, I'm building a small desktop app in VS Std 2005 with C# and .net
2.0. I've managed to get the code together to query the ldap my company
has, but every time I attempt to access a specific property a COM
Exception gets thrown, and I can't figure out why. This is a desktop
app.

example("ldap.example.com", "ou=People,dc=example,dc=com");

public void example(string server, string ou) {
searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + server
+ "/" + ou, "", "", AuthenticationTypes.ReadonlyServer));

searcher.Filter = "(uid=wsmith)";
SearchResultCollection results = searcher.FindAll();
Console.WriteLine((string)results[0].GetDirectoryEntry().Properties["gPhotoID"]);
// OFFENDING LINE!
}

So that's pretty much the smallest bit of code I can use and get the
error. All the other properties I've tried to access so far have worked
just fine, I've even found some properties to be a collection of values
which works just fine. The gPhotoID should contain a url to a picture
which would look like
"http://intranet.example.com/employees/pictures/18273010.JPG".

The error that I'm getting is:
System.Runtime.InteropServices.COMException was unhandled
Message="Unknown error (0x8000500c)"
Source="System.DirectoryServices"
ErrorCode=-2147463156
StackTrace:
at
System.DirectoryServices.PropertyValueCollection.PopulateList()
at
System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry
entry, String propertyName)
at
System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Entry()
at
System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Current()
at UserManager.UserFactory.Find(String criteria) in D:\My
Documents\Visual Studio
2005\Projects\UserManager\UserManager\UserFactory.cs:line 58
at UserManager.UserFactory.FindByUnix(String unix) in D:\My
Documents\Visual Studio
2005\Projects\UserManager\UserManager\UserFactory.cs:line 26
at UserManagerTest.Program.Main(String[] args) in D:\My
Documents\Visual Studio
2005\Projects\UserManagerTest\UserManagerTest\Program.cs:line 10
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[]
args)
at System.AppDomain.ExecuteAssembly(String assemblyFile,
Evidence assemblySecurity, String[] args)
at
Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object
state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

I can't seem to find a solution. I've been googling for over an hour,
and most of the answers I find pertain to credential issues, and
asp.net issues. Can someone please offer assistance?

Thanks,
Will

I'm getting the exact same problem. I can read all properties in the
entire directory except for two specific ones which coincidentally were
only recently added to the schema. For those two properties I can't
even enumerate them my loop. As soon as the loop steps to those
properties, boom. Still investigating.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top