【发布时间】:2017-01-30 18:38:43
【问题描述】:
我创建了一个以 Rest 格式导出数据的活动目录 API。
虽然代码本身运行起来很慢,但我尝试了几种方法从我们的活动目录中获取数据,但处理速度几乎没有变化。
在目前的形式中,每 1000 个用户需要将近 15 秒的时间来检索它们并序列化它们的属性,然后返回数据。
所以我的问题是,是否有人可以帮助我弄清楚如何优化此过程并减少加载时间。我现在能想到的唯一解决方案是将数据直接存储在服务器 RAM 中,并使用线程以间隔更新它。
这就是现在的样子:
获取用户的类:
public List<ADUserDetail> GetUserFromGroup(String groupName)
{
List<ADUserDetail> userlist = new List<ADUserDetail>();
try
{
var context = new PrincipalContext(
ContextType.Domain,
"domain", @"username", "password");
using (var group = GroupPrincipal.FindByIdentity(context, groupName))
{
var users = group.GetMembers(true);
int i = 1;
foreach (UserPrincipal user in users)
{
ADUserDetail userobj = ADUserDetail.GetProp(user);
Debug.WriteLine(i + " " + userobj.sAMAccountName);
i++;
userlist.Add(userobj);
}
}
return userlist;
}
catch (Exception ex)
{
Debug.WriteLine(ex);
return userlist;
}
}
因此您可以看出,此方法从组中获取所有用户并为每个用户创建一个 ADUserDetail 对象,最终返回这些对象的列表。
我在这里尝试了不同的方法,使用 Directorysearcher,但响应时间几乎与 UserPrincipal 相同。
ADUserDetail 看起来像这样:
public ADUserDetail()
{
_Groups = new List<string>();
}
public static ADUserDetail GetProp(UserPrincipal directoryUser)
{
return new ADUserDetail(directoryUser);
}
private static String GetProperty(UserPrincipal userDetail, String propertyName)
{
if (userDetail.GetProperty(propertyName) != null)
{
return userDetail.GetProperty(propertyName);
}
else
{
return string.Empty;
}
}
private ADUserDetail(UserPrincipal directoryUser)
{
String domainAddress;
String domainName;
_Groups = new List<string>();
var groups = directoryUser.GetGroups();
IEnumerable<string> groupNames = groups.Select(x => x.SamAccountName);
foreach (string name in groupNames)
{
_Groups.Add(name);
}
_firstName = GetProperty(directoryUser, ADProperties.FIRSTNAME);
_middleName = GetProperty(directoryUser, ADProperties.MIDDLENAME);
_lastName = GetProperty(directoryUser, ADProperties.LASTNAME);
_sAMAccountName = GetProperty(directoryUser, ADProperties.SAMACCOUNTNAME);
String userPrincipalName = GetProperty(directoryUser, ADProperties.USERPRINCIPALNAME);
if (!string.IsNullOrEmpty(userPrincipalName))
{
domainAddress = userPrincipalName.Split('@')[1];
}
else
{
domainAddress = String.Empty;
}
if (!string.IsNullOrEmpty(domainAddress))
{
domainName = domainAddress.Split('.').First();
}
else
{
domainName = String.Empty;
}
_streetAddress = GetProperty(directoryUser, ADProperties.STREETADDRESS);
_city = GetProperty(directoryUser, ADProperties.CITY);
_state = GetProperty(directoryUser, ADProperties.STATE);
_postalCode = GetProperty(directoryUser, ADProperties.POSTALCODE);
_country = GetProperty(directoryUser, ADProperties.COUNTRY);
_company = GetProperty(directoryUser, ADProperties.COMPANY);
_department = GetProperty(directoryUser, ADProperties.DEPARTMENT);
_homePhone = GetProperty(directoryUser, ADProperties.HOMEPHONE);
_extension = GetProperty(directoryUser, ADProperties.EXTENSION);
_mobile = GetProperty(directoryUser, ADProperties.MOBILE);
_fax = GetProperty(directoryUser, ADProperties.FAX);
_emailAddress = GetProperty(directoryUser, ADProperties.EMAILADDRESS);
_title = GetProperty(directoryUser, ADProperties.TITLE);
_manager = GetProperty(directoryUser, ADProperties.MANAGER);
_adminDescription = GetProperty(directoryUser, ADProperties.ADMINDESCRIPTION);
_cn = GetProperty(directoryUser, ADProperties.CONTAINERNAME);
_company = GetProperty(directoryUser, ADProperties.COMPANY);
_department = GetProperty(directoryUser, ADProperties.DEPARTMENT);
_displayName = GetProperty(directoryUser, ADProperties.DISPLAYNAME);
_distinguishedName = GetProperty(directoryUser, ADProperties.DISTINGUISHEDNAME);
_homeDirectory = GetProperty(directoryUser, ADProperties.HOMEDIRECTORY);
_homeDrive = GetProperty(directoryUser, ADProperties.HOMEDRIVE);
_homeMDB = GetProperty(directoryUser, ADProperties.HOMEMDB);
_homeMTA = GetProperty(directoryUser, ADProperties.HOMEMTA);
_info = GetProperty(directoryUser, ADProperties.INFO);
_mail = GetProperty(directoryUser, ADProperties.EMAILADDRESS);
_mailNickname = GetProperty(directoryUser, ADProperties.MAILNICKNAME);
_manager = GetProperty(directoryUser, ADProperties.MANAGER);
_mDBUseDefaults = GetProperty(directoryUser, ADProperties.MDBUSEDEFAULTS);
_mobile = GetProperty(directoryUser, ADProperties.MOBILE);
_name = GetProperty(directoryUser, ADProperties.NAME);
_neEmployeeNumber = GetProperty(directoryUser, ADProperties.NEEMPLOYEENUMBER);
_neEdirDn = GetProperty(directoryUser, ADProperties.NEEDIRDN);
_objectCategory = GetProperty(directoryUser, ADProperties.OBJECTCATEGORY);
_objectClass = "Placeholder";;
_primaryGroupID = GetProperty(directoryUser, ADProperties.PRIMARYGROUPID);
_proxyAddresses = "Placeholder"; ;
_sAMAccountType = GetProperty(directoryUser, ADProperties.SAMACCOUNTTYPE);
_showInAddressBook = "Placeholder"; ;
_streetAddress = GetProperty(directoryUser, ADProperties.STREETADDRESS);
_telephoneNumber = GetProperty(directoryUser, ADProperties.TELEPHONENUMBER);
_title = GetProperty(directoryUser, ADProperties.TITLE);
_userPrincipalName = GetProperty(directoryUser, ADProperties.USERPRINCIPALNAME);
_employeeID = GetProperty(directoryUser, ADProperties.EMPLOYEEID);
_c = GetProperty(directoryUser, ADProperties.COUNTRYNOTATION);
_postalCode = GetProperty(directoryUser, ADProperties.POSTALCODE);
_physicalDeliveryOfficeName = GetProperty(directoryUser, ADProperties.PHYSICALDELIVERYOFFICENAME);
_instanceType = GetProperty(directoryUser, ADProperties.INSTANCETYPE);
_whenCreated = GetProperty(directoryUser, ADProperties.WHENCREATED);
_whenChanged = GetProperty(directoryUser, ADProperties.WHENCHANGED);
_memberOf = "PlaceHolder";//GetProperty(directoryUser, ADProperties.MEMBEROF);
_directReports = GetProperty(directoryUser, ADProperties.DIRECTREPORTS);
_userAccountControl = GetProperty(directoryUser, ADProperties.USERACCOUNTCONTROL);
_codePage = GetProperty(directoryUser, ADProperties.CODEPAGE);
_countryCode = GetProperty(directoryUser, ADProperties.COUNTRYCODE);
_adminCount = GetProperty(directoryUser, ADProperties.ADMINCOUNT);
_logonCount = GetProperty(directoryUser, ADProperties.LOGONCOUNT);
_legacyExchangeDN = GetProperty(directoryUser, ADProperties.LEGACYEXCHANGEDN);
_servicePrincipalName = GetProperty(directoryUser, ADProperties.SERVICEPRINCIPALNAME);
_dSCorePropagationData = "Placeholder";
_pager = GetProperty(directoryUser, ADProperties.PAGER);
_homePhone = GetProperty(directoryUser, ADProperties.HOMEPHONE);
_msExchUserAccountControl = GetProperty(directoryUser, ADProperties.MSEXCHUSERACCOUNTCONTROL);
_msExchPoliciesIncluded = GetProperty(directoryUser, ADProperties.MSEXCHPOLICIESINCLUDED);
_msExchRecipientDisplayType = GetProperty(directoryUser, ADProperties.MSEXCHRECIPIENTDISPLAYTYPE);
if (!String.IsNullOrEmpty(_manager))
{
String[] managerArray = _manager.Split(',');
_managerName = managerArray[0].Replace("CN=", "");
}
}
AdUserdetail 中的所有属性声明如下所示:
[DataMember]
private String _firstName;
[DataMember]
private String _middleName;
[DataMember]
private String _lastName;
接着是:
public String FirstName
{
get { return _firstName; }
}
public String MiddleName
{
get { return _middleName; }
}
public String LastName
{
get { return _lastName; }
}
所有属性都以这种方式声明并使用 DataMember 进行序列化。
这里提示的第三个类是 ADProperties 类。然而,它只是一个常量类,更容易跟踪属性名称,它看起来像这样:
public const String ADMINDESCRIPTION = "adminDescription";
public const String FIRSTNAME = "givenName";
public const String MIDDLENAME = "initials";
等等。
这一切都由这样的 API 控制器调用:
public HttpResponseMessage Get()
{
ActiveDirectorySearcher ADSearcher = new ActiveDirectorySearcher();
var Users = ADSearcher.GetUserFromGroup("NameofGroup");
if (Users != null)
{
return Request.CreateResponse(HttpStatusCode.OK, Users);
}
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Users found");
}
看起来就是这样,我们的 AD 非常大,有超过 30k 的用户,在一些预定的工作中,这个 API 需要响应多达 5k 的用户,在当前状态下它需要将近 70 秒来执行此操作,并且我想把时间缩短到 10 秒以下。但到目前为止,我的尝试都没有结果。到目前为止,绝大多数处理时间都发生在序列化过程中。
【问题讨论】:
标签: c# asp.net xml rest active-directory