Я пытаюсь получить рекурсивно все прямые отчеты пользователя через Active Directory. Поэтому, учитывая пользователя, я получаю список всех пользователей, у которых есть этот человек в качестве менеджера, или у кого есть лицо в качестве менеджера, у которого есть человек в качестве менеджера... у которого в конечном итоге есть пользователь ввода в качестве менеджера.
Моя текущая попытка довольно медленная:
private static Collection<string> GetDirectReportsInternal(string userDN, out long elapsedTime)
{
Collection<string> result = new Collection<string>();
Collection<string> reports = new Collection<string>();
Stopwatch sw = new Stopwatch();
sw.Start();
long allSubElapsed = 0;
string principalname = string.Empty;
using (DirectoryEntry directoryEntry = new DirectoryEntry(string.Format("LDAP://{0}",userDN)))
{
using (DirectorySearcher ds = new DirectorySearcher(directoryEntry))
{
ds.SearchScope = SearchScope.Subtree;
ds.PropertiesToLoad.Clear();
ds.PropertiesToLoad.Add("directReports");
ds.PropertiesToLoad.Add("userPrincipalName");
ds.PageSize = 10;
ds.ServerPageTimeLimit = TimeSpan.FromSeconds(2);
SearchResult sr = ds.FindOne();
if (sr != null)
{
principalname = (string)sr.Properties["userPrincipalName"][0];
foreach (string s in sr.Properties["directReports"])
{
reports.Add(s);
}
}
}
}
if (!string.IsNullOrEmpty(principalname))
{
result.Add(principalname);
}
foreach (string s in reports)
{
long subElapsed = 0;
Collection<string> subResult = GetDirectReportsInternal(s, out subElapsed);
allSubElapsed += subElapsed;
foreach (string s2 in subResult)
{
result.Add(s2);
}
}
sw.Stop();
elapsedTime = sw.ElapsedMilliseconds + allSubElapsed;
return result;
}
По существу, эта функция принимает выделенное имя как вход (CN = Michael Stum, OU = test, DC = sub, DC = domain, DC = com), и при этом вызов ds.FindOne() медленный.
Я обнаружил, что намного быстрее искать userPrincipalName. Моя проблема: sr.Properties [ "directReports" ] - это всего лишь список строк, и это различающееся имя, которое кажется медленным для поиска.
Интересно, есть ли быстрый способ конвертировать между выдающимся именем и userPrincipalName? Или существует ли более быстрый способ поиска пользователя, если у меня есть только отличительное имя?
Изменить: Благодаря ответу! Поиск в поле "Менеджер" улучшил функцию с 90 секунд до 4 секунд. Вот новый и улучшенный код, который быстрее и читабельнее (обратите внимание, что в функциях elapsedTime, скорее всего, есть ошибка, но фактическое ядро функции работает):
private static Collection<string> GetDirectReportsInternal(string ldapBase, string userDN, out long elapsedTime)
{
Collection<string> result = new Collection<string>();
Stopwatch sw = new Stopwatch();
sw.Start();
string principalname = string.Empty;
using (DirectoryEntry directoryEntry = new DirectoryEntry(ldapBase))
{
using (DirectorySearcher ds = new DirectorySearcher(directoryEntry))
{
ds.SearchScope = SearchScope.Subtree;
ds.PropertiesToLoad.Clear();
ds.PropertiesToLoad.Add("userPrincipalName");
ds.PropertiesToLoad.Add("distinguishedName");
ds.PageSize = 10;
ds.ServerPageTimeLimit = TimeSpan.FromSeconds(2);
ds.Filter = string.Format("(&(objectCategory=user)(manager={0}))",userDN);
using (SearchResultCollection src = ds.FindAll())
{
Collection<string> tmp = null;
long subElapsed = 0;
foreach (SearchResult sr in src)
{
result.Add((string)sr.Properties["userPrincipalName"][0]);
tmp = GetDirectReportsInternal(ldapBase, (string)sr.Properties["distinguishedName"][0], out subElapsed);
foreach (string s in tmp)
{
result.Add(s);
}
}
}
}
}
sw.Stop();
elapsedTime = sw.ElapsedMilliseconds;
return result;
}