Active Directory Tip #3 – Get DirectoryEntry Property with range fetch
Tip #2 already dealt with one of the problems while using multi-value properties.But there is another pitfall that got me once - and usually only happens in production environments and is very hard to debug. I am talking about property range fetch a mechanism introduced to allow the active directory server to use certain optimizations. Unfortunatelly the optimization means a harder to understand API and more work for us programmer.
When dealing with multi-value properties with a huge number of values the active directory server will only return a certain amount of values on the first access (usually 1500 items). On some properties these values don't have an order so that there is a certain randomness to which values are returned - and therefore a certain randomness if your code works as expected or not. Which makes spotting the problem so hard.
So instead of relying on the fact that directoryEntry.Properties["member"] will return all values one must use the range fetch method using DirectorySearcher in order to get all values for said property. In the code sample below I used a cutoff value to determine if simple access should be trusted or if range fetch (slower) must be used.
-
public static readonly int ATTRIBUTE_RANGE_FETCH_CUTOFF = 500;
-
-
public static List<object> GetAdObjectProperties(DirectoryEntry entry, string propertyName)
-
{
-
-
-
if (entry.Properties.Contains(propertyName))
-
{
-
int count = entry.Properties[propertyName].Count;
-
-
if (count == 0)
-
{
-
// Nothing to do.
-
}
-
if (count == 1)
-
{
-
result.Add(entry.Properties[propertyName].Value.ToString());
-
}
-
else if (count <ATTRIBUTE_RANGE_FETCH_CUTOFF)
-
{
-
foreach (object value in entry.Properties[propertyName])
-
{
-
result.Add(value.ToString());
-
}
-
}
-
else
-
{
-
return GetAdObjectPropertiesWithRangeFetch(entry, propertyName);
-
}
-
}
-
-
return result;
-
}
-
-
private static List<object> GetAdObjectPropertiesWithRangeFetch(DirectoryEntry entry, string propertyName)
-
{
-
int index = 0;
-
-
int step = entry.Properties[propertyName].Count - 1;
-
string rangeFormatString = propertyName + ";range={0}-{1}";
-
-
string currentRange = string.Format(rangeFormatString, 0, step);
-
-
{
-
SearchResult searchResult = FindCurrentRange(searcher, currentRange);
-
-
while ((searchResult != null) && searchResult.Properties.Contains(currentRange))
-
{
-
foreach (object item in searchResult.Properties[currentRange])
-
{
-
if (item != null)
-
{
-
result.Add(item);
-
}
-
index++;
-
}
-
-
currentRange = string.Format(rangeFormatString, index, (index + step));
-
-
searchResult = FindCurrentRange(searcher, currentRange);
-
}
-
-
if (searchResult != null)
-
{
-
// final search with '*' as upper limit
-
string finalRange = string.Format(rangeFormatString, index, "*");
-
searchResult = FindCurrentRange(searcher, finalRange);
-
-
foreach (object item in searchResult.Properties[finalRange])
-
{
-
if (item != null)
-
{
-
result.Add(item);
-
}
-
}
-
}
-
-
return result;
-
}
-
}
-
-
private static SearchResult FindCurrentRange(DirectorySearcher searcher, string currentRange)
-
{
-
searcher.PropertiesToLoad.Clear();
-
searcher.PropertiesToLoad.Add(currentRange);
-
-
SearchResult searchResult = searcher.FindOne();
-
return searchResult;
-
}

blah
Comment on September 1, 2011 @ 20:41:05