从__ComObject获取无法使用的方法

问题描述:

我正在优化我们用来查询Active Directory的一些代码。其中一种方法可以获取自特定更新以来发生更改的所有AD用户,这些用户由Directory Entry的uSNCreated属性确定。本质上,它在做的C#等价的:从__ComObject获取无法使用的方法

SELECT * FROM PrincipalSearcher其中uSNCreated> someValue中

的代码是(或多或少):

public IEnumerable<UserPrincipal> GetUpdatedUsers(string samAccountName, long lastUsnChanged) 
{ 
    using (var context = new PrincipalContext(ContextType.Domain)) 
    using (var userSearcher = new PrincipalSearcher(new UserPrincipal(context))) 
    { 
     var items = userSearcher.FindAll().Cast<UserPrincipal>(); 
     return items.Where(x => GetUsnChanged(x) > lastUsnChanged).ToArray(); 
    } 
} 

private static long GetUsnChanged(Principal item) 
{ 
    var de = item.GetUnderlyingObject() as DirectoryEntry; 
    if (de == null) 
     return 0; 

    if (!de.Properties.Contains("uSNCreated")) 
     return 0; 

    var usn = de.Properties["uSNCreated"].Value; 
    var t = usn.GetType(); 

    var highPart = (int)t.InvokeMember("HighPart", BindingFlags.GetProperty, null, usn, null); 
    var lowPart = (int)t.InvokeMember("LowPart", BindingFlags.GetProperty, null, usn, null); 

    return highPart * ((long)uint.MaxValue + 1) + lowPart; 
} 

现在,这个代码不工作,但对InvokeMember()的重复调用是SLOW。我想要做的是获取对HighPart和LowPart属性的引用,这样我就可以反复调用它们,而无需每次调用​​InvokeMember()时都需要“重新发现”它们的开销。

我,虽然我可以做沿着

static PropertyInfo highProp = highProp 
    ?? t.GetProperty("HighPart", BindingFlags.GetProperty); 
highPart = (int)highProp.GetValue(usn); 

Unfortnately t.GetProperty东西线()始终返回null。查看GetProperties(),GetMethods()和GetMembers()返回的结果,即使使用BindingFlags.NonPublic - __ComObject,也不会出现可见的“HighPart”或“LowPart”似乎没有暴露他们(即使我可以调用使用InvokeMember())

有没有办法解决这个问题,还是该承认失败的时候了?

+1

您可以复制/粘贴[接口声明](https://referencesource.microsoft.com/#System.Web/Security/ADMembershipProvider.cs,96419c0a980e9d0e)。或者添加对c:\ windows \ system32 \ activeds.tlb的引用。将Value属性的返回值转换为此接口。这实际上更快的可能性并不高,你肯定会看到网络往返域控制器的成本。 –

+0

你说得对,这似乎并没有为性能做任何事情,但它确实使代码更具可读性。这在我的书中值得+1,谢谢! – Pete

System.DirectoryServices.AccountManagement命名空间中的类是为简单情况而设计的,例如, G。你需要找到一个用户或组。这些类已知性能问题。我建议使用DirectorySearcher或LdapConnection/SearchRequest。在这种情况下,您可以过滤服务器上的对象,而不是客户端,这会显着提高性能并减少通过网络发送的数据。以下是使用DirectorySearcher查找所有用户的示例:Get all users from AD domain 在您的情况下,过滤器将看起来像(&(object = Class)(uSNCreated> = x + 1))其中x是您的最后一个usn。 请注意,如果您使用usnCreated属性跟踪对象,则只会获取自上次usn后创建的用户。要跟踪更改,请使用usnChanged属性

+0

对uSNCreated与uSNChanged的良好通话。我尝试过使用DirectorySeacher,但一直得到抛出的ArgumentException异常,抱怨“(&((objectClass = user)(uSNChanged> 132440887)))搜索过滤器无效。”我会继续与此插件 - 我更喜欢服务器端筛选结果的想法 – Pete

+0

替换> with> =在过滤器中,并增加一个 – oldovets

+0

我绝对gobsmacked! DirectorySearcher无法处理>运算符?这很了不起,但你是对的。这就像一个魅力 - 谢谢! – Pete