2010-03-09 7 views
3

J'ai un programme qui me permet de gérer les utilisateurs sur notre serveur terminal que nous utilisons pour faire la démonstration de notre logiciel. J'ai essayé d'améliorer le performace d'ajouter des utilisateurs au système (il ajoute le compte principal puis il ajoute des sous-comptes si nécessaire, par exemple si j'avais un utilisateur de Demo1 et 3 sous utilisateurs il créerait Demo1, Demo1a, Demo1b, et Demo1c.)Amélioration des performances de System.DirectoryServices.AccountManagement

private void AddUsers(UserInfo userInfo, InfinityInfo infinityInfo, int subUserStart) 
{ 
    using (GroupPrincipal r = GroupPrincipal.FindByIdentity(context, "Remote Desktop Users")) 
    using (GroupPrincipal u = GroupPrincipal.FindByIdentity(context, "Users")) 
    for(int i = subUserStart; i < userInfo.SubUsers; ++i) 
    { 
     string username = userInfo.Username; 
     if (i >= 0) 
     { 
      username += (char)('a' + i); 
     } 
     UserPrincipal user = null; 
     try 
     { 
      if (userInfo.NewPassword == null) 
       throw new ArgumentNullException("userInfo.NewPassword", "userInfo.NewPassword was null"); 
      if (userInfo.NewPassword == "") 
       throw new ArgumentOutOfRangeException("userInfo.NewPassword", "userInfo.NewPassword was empty"); 

      user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username); 
      if (user == null) 
      { 
       user = new UserPrincipal(context, username, userInfo.NewPassword, true); 
       user.UserCannotChangePassword = true; 
       user.PasswordNeverExpires = true; 
       user.Save(); 
       r.Members.Add(user); 
       u.Members.Add(user); 
      } 
      else 
      { 
       user.Enabled = true; 
       user.SetPassword(userInfo.NewPassword); 
      } 
      IADsTSUserEx iad = (IADsTSUserEx)((DirectoryEntry)user.GetUnderlyingObject()).NativeObject; 
      iad.TerminalServicesInitialProgram = GenerateProgramString(infinityInfo); 
      iad.TerminalServicesWorkDirectory = Service.Properties.Settings.Default.StartInPath; 
      iad.ConnectClientDrivesAtLogon = 0; 
      user.Save(); 
      r.Save(); 
      u.Save(); 
      OperationContext.Current.GetCallbackChannel<IRemoteUserManagerCallback>().FinishedChangingUser(username); 

     } 
     catch (Exception e) 
     { 
      string errorString = String.Format("Could not Add User:{0} Sub user:{1}", userInfo.Username, i); 
      try 
      { 
       if (user != null) 
        errorString += "\nSam Name: " + user.SamAccountName; 
      } 
      catch { } 
      OperationContext.Current.GetCallbackChannel<IRemoteUserManagerCallback>().UserException(errorString, e); 
     } 
     finally 
     { 
      if (user != null) 
       user.Dispose(); 
     } 
    } 
} 

pas à pas dans le code que j'ai trouvé que user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username); est l'appel coûteux, en 5-10 secondes par boucle.

J'ai trouvé que j'avais 5-10 secondes de plus sur chaque appel GroupPrincipal.FindByIdentity() aussi, donc je l'ai déplacé hors de la boucle, le Save() n'est pas cher. Avez-vous d'autres recommandations pour accélérer ce processus?

Éditer - Le cas normal serait l'utilisateur existera mais il est probable que le sous-utilisateur n'existe pas, mais il peut exister.

Répondre

3

J'ai trouvé un Soulution

private void AddUsers(UserInfo userInfo, InfinityInfo infinityInfo, int subUserStart) 
{ 
    var userSerach = new UserPrincipal(context); 
    userSerach.SamAccountName = userInfo.Username + '*'; 
    var ps = new PrincipalSearcher(userSerach); 
    var pr = ps.FindAll().ToList().Where(a => 
       Regex.IsMatch(a.SamAccountName, String.Format(@"{0}\D", userInfo.Username))).ToDictionary(a => a.SamAccountName); // removes results like conversons12 from the search conversions1* 
    pr.Add(userInfo.Username, Principal.FindByIdentity(context, IdentityType.SamAccountName, userInfo.Username)); 
    using (GroupPrincipal r = GroupPrincipal.FindByIdentity(context, "Remote Desktop Users")) 
    using (GroupPrincipal u = GroupPrincipal.FindByIdentity(context, "Users")) 
    for(int i = subUserStart; i < userInfo.SubUsers; ++i) 
    { 
     string username = userInfo.Username; 
     if (i >= 0) 
     { 
      username += (char)('a' + i); 
     } 
     UserPrincipal user = null; 
     try 
     { 
      if (userInfo.NewPassword == null) 
       throw new ArgumentNullException("userInfo.NewPassword", "userInfo.NewPassword was null"); 
      if (userInfo.NewPassword == "") 
       throw new ArgumentOutOfRangeException("userInfo.NewPassword", "userInfo.NewPassword was empty"); 
      if (pr.ContainsKey(username)) 
      { 
       user = (UserPrincipal)pr[username]; 
       user.Enabled = true; 
       user.SetPassword(userInfo.NewPassword); 
      } 
      else 
      { 
       user = new UserPrincipal(context, username, userInfo.NewPassword, true); 
       user.UserCannotChangePassword = true; 
       user.PasswordNeverExpires = true; 
       user.Save(); 
       r.Members.Add(user); 
       u.Members.Add(user); 
       r.Save(); 
       u.Save(); 
      } 
      IADsTSUserEx iad = (IADsTSUserEx)((DirectoryEntry)user.GetUnderlyingObject()).NativeObject; 
      iad.TerminalServicesInitialProgram = GenerateProgramString(infinityInfo); 
      iad.TerminalServicesWorkDirectory = Service.Properties.Settings.Default.StartInPath; 
      iad.ConnectClientDrivesAtLogon = 0; 
      user.Save(); 
      OperationContext.Current.GetCallbackChannel<IRemoteUserManagerCallback>().FinishedChangingUser(username); 

     } 
     finally 
     { 
      if (user != null) 
      { 
       user.Dispose(); 
      } 
     } 
    } 
} 

Il ajoute quelques secondes sur le premier utilisateur, mais maintenant ses environ 0,5 secondes par utilisateur après. L'appel impair du ps.FindAll().ToList().Where(a =>Regex.IsMatch(...))).ToDictionary(a => a.SamAccountName); est dû au fait qu'un chercheur principal ne cache pas les résultats. Voir my question d'il y a quelques jours.

Questions connexes