3

C#で非同期/並列実行を理解し、Stackoverflowでasync/awaitチュートリアルと解答を読むのに2日ほどかかりました。それでも私のコードで動作させることはできません。私は タスクの戻り値を使用するとInvalidCastExceptionが発生する

はWPF UIをブロックすることなく非同期PrincipalSearcherを通じて、Active Directoryの検索を実行して、必要なもの

実装_activeDirectory

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*/ 
    { 
     ... 
    } 
} 

クラス:

  • await

    public PrincipalSearchResult<Principal> FindGroup(String pattern) 
    { 
        ... 
        PrincipalSearchResult<Principal> searchResult = searcher.FindAll(); 
        return searchResult; 
    } 
    

    問題は、タスクが完了するのを待つていないようです。 searchTask.IsCompletedは待って​​いるラインの後で真ですが、完了するのにほとんど時間がかからず、同期して実行すると検索に約5秒かかります。

  • foreachループの先頭に投げられた場合に例外:

System.InvalidCastException occurred HResult=-2147467262
Message=Unable to cast COM object of type 'System.__ComObject' to interface type 'IDirectorySearch'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{109BA8EC-92F0-11D0-A790-00C04FD8D5A8}' failed due to the following error: No such interface supported (Exception from 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()はおそらくそれが関連している場合でもタスクを返すでしょう。被験者全体はまだ私には霧がかかっています。

質問

  • タスクが完了するのはなぜawaitが待機しませんか?
  • 例外の理由は何ですか?
+0

http://stackoverflow.com/questions/18110738/passing-collection-from-backgroundworker-dowork-to-backgroundworker-completed-an –

+0

@Gosha_Fighten私はすでにしようとした 'PrincipalSearchResult のSearchResult =(PrincipalSearchResult )searchTaskを待ちます; '。これは問題を解決しませんでした。 – mrplow

答えて

2

_activeDirectoryは、オブジェクトを作成する場所以外のスレッドでは使用できません。

これは、オブジェクト内で使用されるCOMホストが実装される方法に基づいています。 COMホストの中には、複数のスレッドで使用できるように実装されているものもあれば、作成された同じスレッドでのみオブジェクトを使用できるように実装されているものもあります。

あなたはTask.Runで実行するか、またはそれは、検索メソッド内のアクティブディレクトリにアクセスするために使用されるCOMオブジェクトを作成するための_activeDirectoryの実装を変更するコード内_activeDirectoryを作成するようにコードを変更する必要があります。

また、スレッドにApartmentStateApartmentState.STAがあることを確認する必要があります。それを行う方法はthis questionを参照してください。


例外のために、すぐにawaitの呼び出しが返されます。未処理の例外がタスク内で発生すると、その時点でタスクは終了します。

上で説明したように、作成された場所と同じスレッドでCOMオブジェクトを使用しているときに例外が発生しないため、検索が実行され、同期実行時に5秒かかる。

3

awaitTaskが完了するのを待ちます。 async\awaitパターンとTPLライブラリで逃した唯一の事は、の中にTaskが投げ込まれているということです。それはTaskExceptionプロパティの内部にキャッシュされており、結果を取得した直後にスローされています。

したがって、問題は、あなたがTaskの中で実行しているコードを別のスレッドに実行できないということです。@ NineBerryはこう言います。

Task<PrincipalSearchResult<Principal>> searchTask = Task.Run(() => 
{ 
    // this have to be a local variable inside your task 
    var _activeDirectory = GET_THE_AD(); 
    return _activeDirectory.FindGroup(searchText.Text)); 
} 

か、することができ、あなたのスレッドのsearcher変数ごとに作成する必要があります:あなたは、あなたAD -object Taskは、このような何かを作成する必要があります。

関連する問題