简体   繁体   English

异步 Active Directory 查询

[英]Async Active Directory querying

I'm trying to create an async'ed query to AD using Directory Services (however it doesn't have any natural async methods), but trying to go around it by doing this:我正在尝试使用目录服务创建对 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());
    }

I'm getting errors from VS at runtime when clicking the button:单击按钮时,我在运行时收到来自 VS 的错误:

在此处输入图像描述

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

Is there a proper way to query AD and not block the UI thread...?是否有适当的方法来查询 AD 而不是阻塞 UI 线程...? I have searched for this, can't find anything useful.我已经搜索过这个,找不到任何有用的东西。

The Active Directory classes wrap COM (Component Object Model) objects. Active Directory 类包装 COM(组件 Object 模型)对象。 COM objects often have thread affinity; COM 对象通常具有线程亲和性; they can only exist one thread, and copying them from one thread to another can raise an error.它们只能存在一个线程,将它们从一个线程复制到另一个线程会引发错误。 I'm guessing that this is the case for SearchResultCollection ;我猜这是SearchResultCollection的情况; since it has a Handle property, it probably wraps an unmanaged resource, which is a COM object.由于它有一个Handle属性,它可能包装了一个非托管资源,即 COM object。

To avoid the error, copy the data on the original thread where you did the search, and copy it into your own data structure that doesn't wrap any unmanaged resource.为避免该错误,请在您进行搜索的原始线程上复制数据,并将其复制到您自己的不包装任何非托管资源的数据结构中。

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());
}

The above is an approximate example-- you may need slightly different code to copy the properties.上面是一个大概的例子——你可能需要稍微不同的代码来复制属性。 But the overall idea is to not return that SearchResultCollection in a manner where it may cross threads.但总体思路是以可能跨线程的方式返回SearchResultCollection

Also, be sure to Dispose your SeachResultCollection when you are done.此外,请务必在完成后Dispose您的 SeachResultCollection。

Your code works just fine for me when I test it (after changing DC.com to my domain name).当我测试它时,你的代码对我来说很好用(在将DC.com更改为我的域名之后)。 The search is performed successfully, and I'm able to read the results back on the main thread.搜索成功执行,我可以在主线程上读取结果。

Is your LDAP path just LDAP:// followed by your domain name?您的 LDAP 路径是否只是LDAP://后跟您的域名? "Unspecified error" can happen when the LDAP path is malformed.当 LDAP 路径格式错误时,可能会发生“未指定错误”。 For example, if I remove the LDAP:// and just put:例如,如果我删除LDAP://并输入:

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

Then FindAll() throws an "Unspecified error".然后FindAll()抛出一个“未指定的错误”。 So I suspect your problem might be in your LDAP path.所以我怀疑你的问题可能出在你的 LDAP 路径中。

On another note, your code is running in parallel (multi-threaded) because Task.Run runs your code on a new thread.另一方面,您的代码是并行运行的(多线程),因为Task.Run在新线程上运行您的代码。 That's fine, and that's the correct way in your case to move code off of the UI thread so that you don't lock the UI thread.没关系,这是您将代码移出 UI 线程的正确方法,这样您就不会锁定 UI 线程。

But Start() is not running asynchronously .但是Start()不是异步运行的。 The async keyword does not make anything asynchronous by itself. async关键字本身不会使任何东西异步。 It only enables the use of await , which you aren't using anywhere (and DirectorySearcher doesn't support it).它只允许使用await ,您没有在任何地方使用它(并且DirectorySearcher不支持它)。 You will see a compiler warning telling you that Start() will run synchronously.您将看到一个编译器警告,告诉您Start()将同步运行。

So you can remove the async keyword from your method definition:因此,您可以从方法定义中删除async关键字:

public SearchResultCollection Start()

You might benefit from reading Microsoft's articles on Asynchronous programming with async and await .您可能会受益于阅读 Microsoft 关于使用 async 和 await 进行异步编程的文章。 They are quite well written, and it should help you understand the difference between asynchronous and parallel.它们写得很好,它应该可以帮助您理解异步和并行之间的区别。

Thank you, John Wu, for your advise with code it worked.谢谢你,John Wu,你对代码有效的建议。 (pasting code below for other people) (下面为其他人粘贴代码)

If its not too much trouble, could you explain this line of code please (its originally yours, i modified it a little):如果它不是太麻烦,你能解释一下这行代码吗(它最初是你的,我修改了一点):

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