簡體   English   中英

異步 Active Directory 查詢

[英]Async Active Directory querying

我正在嘗試使用目錄服務創建對 AD 的異步查詢(但是它沒有任何自然的異步方法),但嘗試通過執行以下操作圍繞它 go:

    public class Domain
    {
        public async Task<SearchResultCollection> Start()
        {
            DirectoryEntry de = new DirectoryEntry("LDAP://DC.com");
            DirectorySearcher de_searcher = new DirectorySearcher(de);
            de_searcher.Filter = "(&(objectClass=person)(sAMAccountName=USERNAME))";
            de_searcher.SearchScope = SearchScope.Subtree;
            de_searcher.PropertiesToLoad.Add("memberOf");
            de_searcher.PropertiesToLoad.Add("DisplayName");
            SearchResultCollection sResult = de_searcher.FindAll();
            return sResult;
        }
    }

    public async void Button1_Click(object sender, EventArgs e)
    {
        Domain domain_object = new Domain();

        SearchResultCollection searchResult_from_domain = await Task.Run(() => domain_object.Start());
    }

單擊按鈕時,我在運行時收到來自 VS 的錯誤:

在此處輸入圖像描述

在 System.DirectoryServices.DirectoryEntry.Bind(布爾 throwIfFail)
在 System.DirectoryServices.DirectoryEntry.Bind()
在 System.DirectoryServices.DirectoryEntry.get_AdsObject()
在 System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne) > 在 System.DirectoryServices.DirectorySearcher.FindAll()
在 C:\Users\318306735\source\repos\AD_Tool\Form1.cs:line 33 中的 AD_Tool.AD_tool.Domain.d__0.MoveNext()
在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任務任務)
在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任務任務) 在 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()

是否有適當的方法來查詢 AD 而不是阻塞 UI 線程...? 我已經搜索過這個,找不到任何有用的東西。

Active Directory 類包裝 COM(組件 Object 模型)對象。 COM 對象通常具有線程親和性; 它們只能存在一個線程,將它們從一個線程復制到另一個線程會引發錯誤。 我猜這是SearchResultCollection的情況; 由於它有一個Handle屬性,它可能包裝了一個非托管資源,即 COM object。

為避免該錯誤,請在您進行搜索的原始線程上復制數據,並將其復制到您自己的不包裝任何非托管資源的數據結構中。

class MyClass
{
    public string Name { get; set; }
    public string MemberOf { get; set; } 
}

public class Domain
{
    public async Task<List<MyClass>> Start()
    {
        DirectoryEntry de = new DirectoryEntry("DC.com");
        DirectorySearcher de_searcher = new DirectorySearcher(de);
        de_searcher.Filter = "(&(objectClass=person)(sAMAccountName=USERNAME))";
        de_searcher.SearchScope = SearchScope.Subtree;
        de_searcher.PropertiesToLoad.Add("memberOf");
        de_searcher.PropertiesToLoad.Add("DisplayName");
        SearchResultCollection sResult = de_searcher.FindAll();

        var results = sResult.Cast<SearchResult>().Select( r => new MyClass { Name = r.Name, MemberOf = r.MemberOf).ToList();
        return results;
    }
}

public async void Button1_Click(object sender, EventArgs e)
{
    var results = await Task.Run(() => domain_object.Start());
}

上面是一個大概的例子——你可能需要稍微不同的代碼來復制屬性。 但總體思路是以可能跨線程的方式返回SearchResultCollection

此外,請務必在完成后Dispose您的 SeachResultCollection。

當我測試它時,你的代碼對我來說很好用(在將DC.com更改為我的域名之后)。 搜索成功執行,我可以在主線程上讀取結果。

您的 LDAP 路徑是否只是LDAP://后跟您的域名? 當 LDAP 路徑格式錯誤時,可能會發生“未指定錯誤”。 例如,如果我刪除LDAP://並輸入:

DirectoryEntry de = new DirectoryEntry("DC.com");

然后FindAll()拋出一個“未指定的錯誤”。 所以我懷疑你的問題可能出在你的 LDAP 路徑中。

另一方面,您的代碼是並行運行的(多線程),因為Task.Run在新線程上運行您的代碼。 沒關系,這是您將代碼移出 UI 線程的正確方法,這樣您就不會鎖定 UI 線程。

但是Start()不是異步運行的。 async關鍵字本身不會使任何東西異步。 它只允許使用await ,您沒有在任何地方使用它(並且DirectorySearcher不支持它)。 您將看到一個編譯器警告,告訴您Start()將同步運行。

因此,您可以從方法定義中刪除async關鍵字:

public SearchResultCollection Start()

您可能會受益於閱讀 Microsoft 關於使用 async 和 await 進行異步編程的文章。 它們寫得很好,它應該可以幫助您理解異步和並行之間的區別。

謝謝你,John Wu,你對代碼有效的建議。 (下面為其他人粘貼代碼)

如果它不是太麻煩,你能解釋一下這行代碼嗎(它最初是你的,我修改了一點):

List<Maple_results> results = sResult.Cast<SearchResult>().Select(r => new M_results { Displayname = r.Properties["DisplayName"][0].ToString(), Memberof =  r.Properties["memberOf"] }).ToList();

    public class M_results
    {
        public string Displayname { get; set; }
        public ResultPropertyValueCollection Memberof { get; set; }
    }

        public async Task<List<_results>> Start()
    {
        DirectoryEntry de = new DirectoryEntry("LDAP://dc.com");
        DirectorySearcher de_searcher = new DirectorySearcher(de);
        de_searcher.Filter = "(&(objectClass=person)(sAMAccountName=USERNAME))";
        de_searcher.SearchScope = SearchScope.Subtree;
        de_searcher.PropertiesToLoad.Add("memberOf");
        de_searcher.PropertiesToLoad.Add("DisplayName");
        SearchResultCollection sResult = de_searcher.FindAll();

        List<Maple_results> results = sResult.Cast<SearchResult>().Select(r => new M_results { Displayname = r.Properties["DisplayName"][0].ToString(), Memberof =  r.Properties["memberOf"] }).ToList();
        return results;
    }

    private async void Button1_Click(object sender, EventArgs e)
    {
        var results = await Task.Run(() => Start());

        resultTextbox.AppendText(results[0].Memberof[2].ToString() ) ;

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM