PrincipalSearchResult и System.OutOfMemoryException - PullRequest
0 голосов
/ 05 декабря 2018

Я использую домен PrincipalContext для поиска групп пользователей.И я получил это.Но когда я пытаюсь работать с коллекцией групп, я получаю System.OutOfMemoryException.Все основные объекты являются одноразовыми.И есть раздел с использованием в моем коде.Я пытался использовать Dispose() метод и GC.Collect(), но это не помогает.

Вот код:

using (var ctx = new PrincipalContext(ContextType.Domain, _domain, _user, _password))
{
    using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx,IdentityType.SamAccountName, sAMAccountName))
    {
        PrincipalSearchResult<Principal> userGroups = user.GetGroups();                    
        using (userGroups)
        {
            foreach (Principal p in userGroups)
            {
                using (p)
                {
                    result.Add(p.Guid == null ? Guid.Empty : (Guid)p.Guid);
                }
            }
        }
    }
}

исключение возврата цикла foreach.Даже foreach - это пустой цикл.

1 Ответ

0 голосов
/ 05 декабря 2018

Я считаю, что пространство имен 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...