【问题标题】:Fetching more than 1000 rows from Domino LDAP server using .NET Core 5 and Novell.Directory.Ldap.NETStandard使用 .NET Core 5 和 Novell.Directory.Ldap.NETStandard 从 Domino LDAP 服务器获取超过 1000 行
【发布时间】:2021-06-21 19:39:28
【问题描述】:

我想从我们的 Domino LDAP 的一个大位置获取所有用户,总共大约 2000 个用户。由于 .NET Core 遗憾地没有独立于平台的 LDAP 库,因此我将 Novell.Directory.Ldap.NETStandard 与此 POC 一起使用:

var cn = new Novell.Directory.Ldap.LdapConnection();
cn.Connect("dc.internal", 389);
cn.Bind("user", "pw");
string filter = "location=MyLoc";
var result = cn.Search("", Novell.Directory.Ldap.LdapConnection.ScopeOne, filter, new string[] { Novell.Directory.Ldap.LdapConnection.AllUserAttrs }, typesOnly: false);            
int count = 0;
while (result.HasMore()) {
    var entry = result.Next();
    count++;
    Console.WriteLine(entry.Dn);
}

它打印了很多条目,但不是全部。当count = 1000 我得到一个Size Limit Exceeded 异常。我想这是因为我需要使用某种分页,所以并不是所有条目都会在一个请求中返回。有不同的问题,例如thisthis one。在 Java 中,.NET Core API 似乎有些不同。

方法 1:尝试了解 LdapSearchRequest 在 .NET Core 中的工作原理

byte[] resumeCookie = null;
LdapMessageQueue queue = null;
var searchReq = new LdapSearchRequest("", LdapConnection.ScopeOne, filter, new string[] { LdapConnection.AllUserAttrs },
LdapSearchConstraints.DerefNever, maxResults: 3000, serverTimeLimit: 0, typesOnly: false, new LdapControl[] { new SimplePagedResultsControl(size: 100, resumeCookie) });            
var searchRequest = cn.SendRequest(searchReq, queue);

我试图弄清楚如何在 .NET Core 中使用 Java 示例。这看起来不错,但是我不知道如何获取 LDAP 条目。我只得到一个消息ID。 By looking into the source 看来我走对了,但他们使用的是MessageAgent,因为它是internal sealed,所以不能在外面使用。这大概就是为什么在源代码中搜索LdapRearchRequest 没有得到很多结果的原因。

方法二:使用SimplePagedResultsControlHandler

var opts = new SearchOptions("", LdapConnection.ScopeOne, filter, new string[] { LdapConnection.AllUserAttrs });
// For testing purpose: https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard/issues/163
cn.SearchConstraints.ReferralFollowing = false;
var pageControlHandler = new SimplePagedResultsControlHandler(cn);
var rows = pageControlHandler.SearchWithSimplePaging(opts, pageSize: 100);

这会引发Unavaliable Cricital Extension 异常。首先我认为这是 .NET 端口的问题,它可能还不支持原始 Java 库的所有功能。它看起来很完整,根据进一步的研究,它看起来像是一个 LDAP 错误代码。所以这一定是服务器必须支持的东西,但 Domino 不支持。

【问题讨论】:

标签: c# asp.net-core ldap lotus-domino .net-5


【解决方案1】:

我无法使这些方法中的至少一种起作用,但找到了另一种方法:System.DirectoryServices.Protocols 命名空间的跨平台支持是was added in .NET 5。这在 .NET Core 中丢失了很长时间,我想这就是为什么像 Novell.Directory.Ldap.NETStandard 这样的库被移植到 .NET Core 的主要原因 - 在 .NET Core 1.x 时代,这是我发现的唯一身份验证方式反对 LDAP,它也适用于 Linux。

在深入了解System.DirectoryServices.Protocols 之后,它开箱即用,即使对于大约 2k 用户也是如此。我的基本 POC 类如下所示:

public class DominoLdapManager {
    LdapConnection cn = null;
    public DominoLdapManager(string ldapHost, int ldapPort, string ldapBindUser, string ldapBindPassword) {
        var server = new LdapDirectoryIdentifier(ldapHost, ldapPort);
        var credentials = new NetworkCredential(ldapBindUser, ldapBindPassword);

        cn = new LdapConnection(server);
        cn.AuthType = AuthType.Basic;
        cn.Bind(credentials);
    }
    public IEnumerable<DominoUser> Search(string filter, string searchBase = "") {
        string[] attributes = { "cn", "mail", "companyname", "location" };
        var req = new SearchRequest(searchBase, filter, SearchScope.Subtree, attributes);
        var resp = (SearchResponse)cn.SendRequest(req);

        foreach (SearchResultEntry entry in resp.Entries) {
            var user = new DominoUser() {
                Name = GetStringAttribute(entry, "cn"),
                Mail = GetStringAttribute(entry, "mail"),
                Company = GetStringAttribute(entry, "companyname"),
                Location = GetStringAttribute(entry, "location")
            };
            yield return user;
        }
        yield break;
    }
    string GetStringAttribute(SearchResultEntry entry, string key) {
        if (!entry.Attributes.Contains(key)) {
            return string.Empty;
        }
        string[] rawVal = (string[])entry.Attributes[key].GetValues(typeof(string));
        return rawVal[0];
    }
}

示例用法:

var ldapManager = new DominoLdapManager("ldap.host", 389, "binduser", "pw");
var users = ldapManager.Search("objectClass=person");

但正如标题所说,Novell.Directory.Ldap.NETStandard 并没有解决

这并不能解决我使用标题所建议的Novell.Directory.Ldap.NETStandard 库的问题,是的。但由于System.DirectoryServices.Protocols 是由微软和.NET 基金会维护的官方.NET 包,这对我来说似乎是更好的方法。该基金会将注意维护它并与进一步的 .NET 版本兼容。当我写这个问题时,我不知道现在添加了 Linux 支持。

不要误会我的意思,我不想说第三个包的设计不好——那是完全错误的。但是,当我在官方包和第三方包之间进行选择时,我认为更喜欢官方包是有道理的。除非有充分的理由反对 - 这里不是这种情况:官方包(过去不存在)比第三方包更能解决这个问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-22
    • 1970-01-01
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    • 2021-06-16
    • 2019-10-29
    相关资源
    最近更新 更多