2017-01-22 18 views
1

私は現在、使用しようとしている非同期メソッドで予期せぬ/望ましくない動作が発生しています。非同期メソッドはRecognizeAsyncです。 voidを返すので、私はこのメソッドを待つことができません。何が起きているのですか?ProcessAudioメソッドが最初に呼び出され、一見一貫して実行されますが、Webページは決して私の "Contact"ビューを返しません。メソッドが完了すると、ハンドラ内のブレークポイントがヒットし始めます。私が完了まで再生すると、リダイレクトは起こりません - クロムデバッガのネットワークタブでは、 "ステータス"は保留中とマークされたままになります。私は自分の問題が非同期性の問題によって引き起こされていると確信していますが、正確には何かを発見できませんでした。非同期メソッドで予期しない動作が発生しました

すべてのご協力をいただきありがとうございます。

[HttpPost] 
public async Task<ActionResult> ProcessAudio() 
{ 
    SpeechRecognitionEngine speechEngine = new SpeechRecognitionEngine(); 
    speechEngine.SetInputToWaveFile(Server.MapPath("~/Content/AudioAssets/speechSample.wav")); 
    var grammar = new DictationGrammar(); 
    speechEngine.LoadGrammar(grammar); 

    speechEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(SpeechRecognizedHandler); 
    speechEngine.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(SpeechHypothesizedHandler); 

    speechEngine.RecognizeAsync(RecognizeMode.Multiple); 

    return View("Contact", vm); //first breakpoint hit occurs on this line 
            //but it doesnt seem to be executed? 
} 

private void SpeechRecognizedHandler(object sender, EventArgs e) 
{ 
    //do some work 
    //3rd breakpoint is hit here 
} 

private void SpeechHypothesizedHandler(object sender, EventArgs e) 
{ 
    //do some different work 
    //2nd breakpoint is hit here 
} 

UPDATE:提案に基づいて、私は(ProcessAudio中)に自分のコードを変更しました:

using (speechEngine) 
{ 
    speechEngine.SetInputToWaveFile(Server.MapPath("~/Content/AudioAssets/speechSample.wav")); 
    var grammar = new DictationGrammar(); 
    speechEngine.LoadGrammar(grammar); 

    speechEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(SpeechRecognizedHandler); 
    speechEngine.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(SpeechHypothesizedHandler); 
    var tcsRecognized = new TaskCompletionSource<EventArgs>(); 
    speechEngine.RecognizeCompleted += (sender, eventArgs) => tcsRecognized.SetResult(eventArgs); 

    speechEngine.RecognizeAsync(RecognizeMode.Multiple); 
    try 
    { 
     var eventArgsRecognized = await tcsRecognized.Task; 
    } 
    catch(Exception e) 
    { 
     throw (e); 
    } 
} 

、これは、いくつかの間違った行動が生じている: return View("Contact",vm)ブレークポイントは現在、AFTERヒットしますハンドラは終了しますが、リダイレクトはまだ発生しません。私は私の連絡先ページには決して指示されません。以前と同じように無期限にオリジナルページを読み込んでいます。

+0

「await speechEngine.RecognizeAsync(RecognizeMode.Multiple); –

+0

voidを返す非同期メソッドを 'await'しようとするとコンパイラエラーが発生する – GregH

+0

@ErikPhilips新しいスタイルのTAPベースの非同期と交差する命名規則を使用する古いスタイルのイベントベースの非同期です。 'WebClient'もこの不幸な命名の衝突を共有します。 – spender

答えて

0

誰がcurious-であれば、私は次の操作を行って、私の問題を解決:私はになろうとして原因の非同期イベントにInvalidOperationExceptionにつながるRecognize()代わりのRecognizeAsync(..)を使用するように変更し

を「ページライフサイクルの無効な時間」に実行されます。これを克服するために、スレッド内で操作をラップし、スレッドを実行した直後にメインスレッドに戻しました。以下のコード:

using (speechEngine) 
     { 
     var t = new Thread(() => 
     { 
      speechEngine.SetInputToWaveFile(@"C:\AudioAssets\speechSample.wav"); 
      speechEngine.LoadGrammar(dictationGrammar); 

      speechEngine.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(SpeechRecognizedHandler); 
      speechEngine.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(SpeechHypothesizedHandler); 
      speechEngine.Recognize(); 
     }); 
     t.Start(); 
     t.Join(); 

     } 
} 
5

あなたは早すぎます。スピーチエンジンはおそらくreturn View行に当たる頃には始まっていないでしょう。

スピーチエンジンから最終イベントが発生するまで待つ必要があります。最良の方法は、非同期に基づくイベントからTAP-based asynchronyに変換することです。

これはすなわちSpeechRecognizedspeechEngine.RecognizeAsyncが呼び出された後に発射する最後のイベントでなければなりません(私は信じている)のが対処しましょうTaskCompletionSource<T>

を使用することによって達成することができます。私は、最終結果がスピーチエンジンによって計算されたときに発生するイベントであると仮定しています。

だから、最初:

var tcs = new TaskCompletionSource<EventArgs>(); 

は今SpeechRecognizedがインラインラムダスタイルのメソッド宣言使用して、発射されたときに完了するためにそれをフックアップすることができます:...お待ち

speechEngine.SpeechRecognized += (sender, eventArgs) => tcs.SetResult(eventArgs); 

を(...もしも音声が認識されなければ何が起こるのでしょうか?また、SpeechRecognitionRejectedイベントをフックアップし、このタイプのイベントのカスタムExceptionサブクラスを定義する必要があります...ここではそれをRecognitionFailedExceptionと呼んでいます。認識プロセスの、s O我々はTaskCompletionSourceは、すべての結果で完了することを望んでいるだろう)、その後

speechEngine.SpeechRecognitionRejected += (sender, eventArgs) => 
          tcs.SetException(new RecognitionFailedException()); 

speechEngine.RecognizeAsync(RecognizeMode.Multiple); 

、我々はTaskCompletionSourceTaskプロパティをawaitすることができます。

try 
{ 
    var eventArgs = await tcs.Task; 
} 
catch(RecognitionFailedException ex) 
{ 
    //this would signal that nothing was recognized 
} 

は、いくつかの操作を行いますタスクの結果であるEventArgsを処理し、実行可能な結果を​​クライアントに返します。

これを行う過程で、適切に処理する必要があるIDisposableインスタンスを作成しています。だから、

using(SpeechRecognitionEngine speechEngine = new SpeechRecognitionEngine()) 
{ 
    //use the speechEngine with TaskCompletionSource 
    //wait until it's finished 
    try 
    { 
     var eventArgs = await tcs.Task; 
    } 
    catch(RecognitionFailedException ex) 
    { 
     //this would signal that nothing was recognized 
    } 

} //dispose 
+0

提案された変更を反映するために私の答えを更新しました。私が持っている問題を見てください。それはあなたが念頭に置いた実装ですか? – GregH

+0

@peggyこれは、複数の「SpeechHypothesized」イベントがあるためだと仮定しています。あなたは 'SpeechHypothesized'イベントに対処しようとする試みを止めて、私の答えに記載されているイベントを扱うことができますか?(中間結果の一種ではなく**最終結果を表すもの) 'SpeechHypothesized'イベントに対処する方法を理解することができます。 – spender

+0

私は現在の試行をもう一度更新しました。今、ビューが返される前にハンドラーを起動させる(そして私のモデルと私のVMは完璧だと思われますが)何らかの理由でコンタクトページにリダイレクトされていません – GregH

関連する問題