【问题标题】:Get Invokable Method from __ComObject从 __ComObject 获取可调用方法
【发布时间】:2017-10-17 08:54:03
【问题描述】:

我正在优化我们用来查询 Active Directory 的一些代码。其中一种方法获取自特定更新以来已更改的所有 AD 用户,由目录条目的 uSNCreated 属性确定。本质上,它相当于 C#:

select * from PrincipalSearcher where 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() 的重复调用很慢。我想做的是获取对 HighPart 和 LowPart 属性的引用,这样我就可以一遍又一遍地调用它们,而无需每次调用​​ InvokeMember() 时都需要“重新发现”它们。

我想我可以做一些类似的事情

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

不幸的是 t.GetProperty() 总是返回 null。查看 GetProperties()、GetMethods() 和 GetMembers() 返回的结果,似乎没有可见的“HighPart”或“LowPart”,即使使用 BindingFlags.NonPublic - __ComObject 也是如此似乎没有暴露它们(即使我可以调用 using InvokeMember())

有没有办法解决这个问题,还是该认输了?

【问题讨论】:

  • 您可以复制/粘贴interface declaration。或者添加对 c:\windows\system32\activeds.tlb 的引用。将 Value 属性的返回值强制转换为该接口。这实际上更快的可能性并不高,您肯定只是看到网络往返域控制器的成本。
  • 你说得对,这似乎对性能没有任何影响,但它确实使代码更具可读性。这在我的书中值得 +1 - 谢谢!

标签: c# active-directory invoke comobject


【解决方案1】:

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

【讨论】:

  • 关于 uSNCreated 与 uSNChanged 的​​良好通话。我尝试使用 DirectorySeacher,但不断收到 ArgumentException 引发的抱怨,抱怨“(&(&(objectClass=user)(uSNChanged > 132440887))) 搜索过滤器无效。”。不过,我会继续努力——我更喜欢服务器端过滤结果的想法
  • 在过滤器中将 > 替换为 >= 并将最后一个 usn 加一
  • 我简直惊呆了! DirectorySearcher 无法处理 > 运算符???这太棒了,但你是对的。这就像一个魅力 - 谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-10
  • 2012-03-22
  • 2019-01-28
  • 1970-01-01
相关资源
最近更新 更多