GroupPrinciple.FindbyIdentity слишком медленный

Я создал функцию для добавления одного пользователя за раз в определенную группу (администраторы и т. Д.), Но, похоже, слишком долго нужно отвечать на вызовы GroupPrinciple(5-10 секунд) и group.members.add(5-10 секунд) и замедление моего приложения, это занимает почти 15-20 секунд, чтобы ответить, есть ли более быстрый способ сделать это?

private static void Add()
{
 var userContext = new PrincipalContext(ContextType.Domain);
 var user = new UserPrincipal(userContext);
 user.SamAccountName = "c1111111";
 var searcher = new PrincipalSearcher(user);
 user = searcher.FindOne() as UserPrincipal;

var machineContext = new PrincipalContext(ContextType.Machine, "ABCDEFGHI1",
   null, ContextOptions.Negotiate, "c123789", "test123");
var group = GroupPrincipal.FindByIdentity(machineContext,"Administrators"); 

group.Members.Add(user); 

Console.WriteLine("saving group");
group.Save();

}

2 ответа

Я сам разбирался с этим, потому что вы используете одну и ту же группу каждый раз, чтобы узнать, сможете ли вы изменить результаты поиска группы, добавив пользователя и добавив сразу нескольких пользователей.

private static void Add(IEnumerable<UserPrincipal> users)
{
    var machineContext = new PrincipalContext(ContextType.Machine, "ABCDEFGHI1",
       null, ContextOptions.Negotiate, "c123789", "test123");
    var group = GroupPrincipal.FindByIdentity(machineContext,"Administrators"); 
    foreach(var user in users)
    {
        group.Members.Add(user); 
    }
    Console.WriteLine("saving group");
    group.Save();
}

Или другой вариант - найти группу один раз, но затем кэшировать ее. С помощью Task.Run это очень просто, просто запустите задачу в статическом конструкторе, а затем получите результат в вашей функции Add. .Result будет блокироваться до тех пор, пока задача не завершится, а затем сразу после этого. Важная заметка, GroupPrincipal не является потокобезопасным, поэтому вам нужно заблокировать изменения в классе.

static YourClassName()
{
    _administratorsGroup = Task.Run(() =>
    {
        var machineContext = new PrincipalContext(ContextType.Machine, "ABCDEFGHI1",
           null, ContextOptions.Negotiate, "c123789", "test123");
        return GroupPrincipal.FindByIdentity(machineContext,"Administrators"); 
    });
}

private static Task<GroupPrincipal> _administratorsGroup;

private static void Add(UserPrincipal user)
{
    group = _administratorsGroup.Result;
    lock(group)
    {
        group.Members.Add(user); 

        Console.WriteLine("saving group");
        group.Save();
    }
}

Если это будет в потоке пользовательского интерфейса, замените _administratorsGroup.Result с await _administratorsGroup, он также имеет такое же поведение ожидания, но не заблокирует ваш пользовательский интерфейс.

FindAll()намного быстрее для ContextType.Machine. Затем просто отфильтруйте результат по доступному входу: Name, UserPrincipalName, SAMAccountNameили же Sid.Value.

Вариант Linq, непроверенный для ContextType.Domain:

      PrincipalContext principalContext = new PrincipalContext(ContextType.Machine);

// user (input: userSID)
PrincipalSearcher userPrincipalSearcher = new PrincipalSearcher(new UserPrincipal(principalContext));
UserPrincipal userPrincipal = userPrincipalSearcher.FindAll().FirstOrDefault(x => (x is UserPrincipal) && x.Sid.Value == userSID) as UserPrincipal;

// group (input: groupSID)
PrincipalSearcher groupPrincipalSearcher = new PrincipalSearcher(new GroupPrincipal(principalContext));
GroupPrincipal groupPrincipal = groupPrincipalSearcher.FindAll().FirstOrDefault(x => (x is GroupPrincipal) && x.Sid.Value == groupSID) as GroupPrincipal;
Другие вопросы по тегам