Я считаю, что пространство имен System.DirectoryServices.AccountManagement
(UserPrincipal
и т. Д.) Тратит много памяти.Например, каждый раз, когда вы создаете UserPrincipal
или GroupPrincipal
, он запрашивает AD для каждого атрибута, который имеет значение - даже если вы когда-либо используете только один из них.
Если пользователь является членоммного, много групп, это может быть причиной, хотя я все еще удивлен.Возможно, у вашего компьютера просто нет доступной памяти для загрузки всего этого.
Вы можете сделать то же самое и использовать меньше памяти (и, вероятно, меньше времени), непосредственно используя пространство имен System.DirectoryServices
(чтопространство имен AccountManagement
в любом случае используется в фоновом режиме.)
Вот пример, который будет смотреть на атрибут memberOf
пользователя, чтобы найти группы и потянуть Guid
.Это имеет некоторые ограничения, которые я описываю в статье, которую я написал: Поиск всех групп пользователей (этот пример изменен с той, что в этой статье).Однако в большинстве случаев (особенно если у вас есть только один домен в вашей среде и нет доверенных доменов) все будет в порядке.
public static IEnumerable<Guid> GetUserMemberOf(DirectoryEntry de) {
var groups = new List<Guid>();
//retrieve only the memberOf attribute from the user
de.RefreshCache(new[] {"memberOf"});
while (true) {
var memberOf = de.Properties["memberOf"];
foreach (string group in memberOf) {
using (var groupDe = new DirectoryEntry($"LDAP://{group.Replace("/", "\\/")}") {
groupDe.RefreshCache(new[] {"objectGUID"});
groups.Add(new Guid((byte[]) groupDe.Properties["objectGUID"].Value));
}
}
//AD only gives us 1000 or 1500 at a time (depending on the server version)
//so if we've hit that, go see if there are more
if (memberOf.Count != 1500 && memberOf.Count != 1000) break;
try {
de.RefreshCache(new[] {$"memberOf;range={groups.Count}-*"});
} catch (COMException e) {
if (e.ErrorCode == unchecked((int) 0x80072020)) break; //no more results
throw;
}
}
return groups;
}
Вам необходимо передать ему DirectoryEntry
объект пользователя.Если вы знаете distinguishedName
заранее, вы можете использовать его (например, new DirectoryEntry($"LDAP://{distinguishedName}")
).Но если нет, вы можете найти его:
var ds = new DirectorySearcher(
new DirectoryEntry($"LDAP://{_domain}"),
$"(&(objectClass=user)(sAMAccountName={sAMAccountName}))");
ds.PropertiesToLoad.Add("distinguishedName"); //add at least one attribute so it doesn't return everything
var result = ds.FindOne();
var userDe = result.GetDirectoryEntry();
Я заметил, что вы также передаете имя пользователя и пароль на PrincipalContext
.Если это необходимо, конструктор для DirectoryEntry
принимает имя пользователя и пароль, поэтому вы можете обновлять этот код, добавляя его каждый раз при создании нового DirectoryEntry
.