我已经花了将近两天的时间阅读有关async/await的教程和Stackoverflow上的答案,试图理解C#中的异步和并行执行。但是,我仍然无法使我的代码正常工作。
我需要什么
通过PrincipalSearcher异步执行Active Directory搜索,而不会阻塞WPF UI。
实现
protected async void SearchButtonClick()
{
Task<PrincipalSearchResult<Principal>> searchTask = Task.Run(() => _activeDirectory.FindGroup(searchText.Text));
PrincipalSearchResult<Principal> searchResult = await searchTask;
foreach (var foundGroup in searchResult) /*exception thrown here*/
{
...
}
}
_activeDirectory类:
public PrincipalSearchResult<Principal> FindGroup(String pattern)
{
...
PrincipalSearchResult<Principal> searchResult = searcher.FindAll();
return searchResult;
}
问题
await
看起来并没有等待任务完成。searchTask.IsCompleted
在 await 行之后为 true,但这不可能是因为它几乎没有完成所需的时间,如果我同步运行它,则搜索需要约 5 秒。- 在 foreach 循环的开头抛出异常:
System.InvalidCastException 出现 HResult=-2147467262
Message=无法将类型为“System.__ComObject”的 COM 对象强制转换为接口类型“IDirectorySearch”。此操作失败,原因是由于 COM 组件上的 QueryInterface 调用请求接口 IID“{109BA8EC-92F0-11D0-A790-00C04FD8D5A8}”时失败,导致以下错误:不支持此接口 (HRESULT 为 0x80004002(E_NOINTERFACE))。 Source=System.DirectoryServices StackTrace: at System.DirectoryServices.SearchResultCollection.get_SearchObject()
InnerException:
想法
- 我发现这种异常与无效的 SynchronizationContext 有关,但我不知道这怎么会发生在这里。我还在代码的几行上打印了 Thread.CurrentThread.ManagedThreadId,并始终返回相同的 id。
- 我还读到异步方法不应该返回
void
而应该返回Task<T>
,但我不认为这在这里是相关的,因为没有人异步使用 SearchButtonClick()。而且Task.Run()
可能确实返回一个 Task,如果这甚至相关的话。整个主题对我来说仍然很模糊。
问题
- 为什么
await
不等待任务完成? - 异常的原因是什么?
PrincipalSearchResult<Principal> searchResult = (PrincipalSearchResult<Principal>) await searchTask;
,但这并没有解决问题。 - mrplow