[英]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.