Я пытаюсь получить все прямые отчеты пользователя через 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;
}