2012-09-17 28 views
2

我有以下代码需要用户名和密码,然后在计算机上创建用户并将其添加到两个特定组。当我到达组合部分时,它非常慢,我不知道为什么。根据我的日志文件,我最后一次运行说,将用户添加到用户组需要7分钟,但IIS_IUSRS速度非常快。添加到组时,在本地计算机上创建用户非常缓慢

下面是我最初的代码,它调用了做真正工作的方法。我尝试过使用任务来帮助加快检查组的过程,但它仍然运行速度超慢。

public void Apply(Section.User.User user, Action<string> status) 
    { 
     #region Sanity Checks 

     if (user == null) 
     { 
      throw new ArgumentNullException("user"); 
     } 

     if (status == null) 
     { 
      throw new ArgumentNullException("status"); 
     } 
     #endregion 
     _logger.Debug(string.Format("Starting to apply the user with name {0}", user.UserName)); 
     status(string.Format("Applying User {0} to the system.", user.UserName)); 

     using (PrincipalContext pc = new PrincipalContext(ContextType.Machine)) 
     { 

      UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(pc, user.UserName); 
      try 
      { 
       _logger.Debug("Checking if user already exists"); 
       if (userPrincipal == null) 
       { 
        userPrincipal = CreateNewUser(user, pc); 
       } 

       _logger.Debug("Setting user password and applying to the system."); 
       userPrincipal.SetPassword(user.UserPassword); 
       userPrincipal.Save(); 

       Task<PrincipalSearchResult<Principal>> groups = 
        Task<PrincipalSearchResult<Principal>>.Factory.StartNew(userPrincipal.GetGroups); 

       _logger.Debug("Adding user to the groups."); 
       AddUserToGroups(pc, userPrincipal, groups, user.UserType.Equals(UserType.WorkerProcess.ToString()) ? "Administrators" : "Users", "IIS_IUSRS"); 
       AddCurrentUser(user); 
      } 
      finally 
      { 
       if (userPrincipal != null) 
       { 
        userPrincipal.Dispose(); 
       } 
      } 


     } 

    } 

这是我用来创建用户的私有方法,如果它不存在。

private UserPrincipal CreateNewUser(Section.User.User user, PrincipalContext principal) 
    { 
     _logger.Debug("User did not exist creating now."); 
     UserPrincipal newUser = new UserPrincipal(principal) 
      { 
       Name = user.UserName, 
       Description = user.UserDescription, 
       UserCannotChangePassword = false, 
       PasswordNeverExpires = true, 
       PasswordNotRequired = false 
      }; 
     _logger.Debug("User created."); 
     return newUser; 
    } 

下面是组的逻辑。我在每次使用调试器时遇到的有问题的代码上面发表了一段评论。此外,调试日志条目始终是我在挂起之前获得的最后一个条目。

private void AddUserToGroups(PrincipalContext principal, UserPrincipal user, Task<PrincipalSearchResult<Principal>> userGroups, params string[] groups) 
    { 
     groups.AsParallel().ForAll(s => 
      { 
       using (GroupPrincipal gp = GroupPrincipal.FindByIdentity(principal, s)) 
       { 
        _logger.Debug(string.Format("Checking if user is alread in the group.")); 
        if (gp != null && !userGroups.Result.Contains(gp)) 
        { 
         _logger.Debug(string.Format("The user was not a member of {0} adding them now.", gp.Name)); 
         //This is the point that the 7 minute hang starts 
         gp.Members.Add(user); 
         gp.Save(); 

         _logger.Debug(string.Format("User added to {0}.", gp.Name)); 
        } 
       } 
      }); 
    } 

任何帮助,这将不胜感激,因为这项目预计10月发布,但我不能释放与创建用户时7分钟挂起。

+0

我不知道这是你的问题,但PrincipalContext不是[线程安全](http://msdn.microsoft.com/en-us/library/system.directoryservices.accountmanagement.principalcontext.aspx#threadSafetyToggle) 。您使用相同的PrincipalContext同时阅读和书写,这可能是您的问题。 –

+0

当您删除'AsParellel().ForAll'时,执行速度会慢吗? –

+0

在它说“用户不是{0}的成员现在添加它们之前或之后挂起。” –

回答

3

有同样的问题。看来,

gp.Members.Add(user); 

是缓慢的,因为它首先列举组(获得Members),然后才将其添加到集合(这又增加了减速)。

解决的办法是把它想:

UserPrincipal user = this is your user; 
    GroupPrincipal group = this is your group; 

    // this is fast 
    using (DirectoryEntry groupEntry = group.GetUnderlyingObject() as DirectoryEntry) 
    using (DirectoryEntry userEntry = user.GetUnderlyingObject() as DirectoryEntry) 
    {   
     groupEntry.Invoke("Add", new object[] { userEntry.Path }); 
    } 

    //group.Members.Add(user); // and this is slow! 
    //group.Save(); 

只是一个提示 - 与SetPassword创建密码对于我们来说也是非常缓慢的。解决方案是遵循“.NET开发人员指南目录服务编程”中的方法,他们使用从System.DirectoryServices.Protocols使用LdapConnection的低级密码设置。

我们发现的最后一个瓶颈是由User.GetGroups()方法造成的。

无论如何,如果将用户添加到群组的代码对您有所帮助,请放下备注。另外请注意,您并不需要并行执行此操作 - 我知道这是您加速代码的方法,但您并不需要这样做。

+0

非常感谢你,这样更快。也感谢这本书,我认为我们将订购一本供我们使用。 – twreid

相关问题