2012-09-17 27 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

相關問題