適用対象: SDK v4
ミドルウェアは、アダプターとボット ロジックの間に配置されるクラスであり、初期化時にアダプターのミドルウェア コレクションに追加されます。 SDK を使用すると、独自のミドルウェアを記述したり、他のユーザーによって作成されたミドルウェアを追加したりできます。 ボットを出入りするすべてのアクティビティはミドルウェアを通って流れます。
アダプターは、ボット ミドルウェア パイプラインを介して受信アクティビティを処理し、ボットのロジックに誘導してから、もう一度戻します。 各アクティビティがボットを出入りして流れる際、ボット ロジックの実行前と実行後のどちらでも、各ミドルウェアがアクティビティを検査または操作できます。
ミドルウェアに進む前に、 ボットの一般的な 概要と アクティビティの処理方法を理解しておくことが重要です。
ミドルウェアの使用
"ミドルウェアとしてアクションを実装する必要がある場合と、通常のボット ロジックを使用する場合" という質問がよく表示されます。ミドルウェアを使用すると、会話の各 ターン が処理される前と後の両方で、ユーザーの会話フローと対話する追加の機会が提供されます。 ミドルウェアを使用すると、会話に関する情報を格納および取得し、必要に応じて追加の処理ロジックを呼び出すこともできます。 ミドルウェアが役に立つ可能性のある一般的なシナリオを次に示します。
すべてのアクティビティを見たり操作したりする
ボットがすべてのアクティビティ、または特定の種類のすべてのアクティビティに対して何かを行う必要がある状況は多数あります。 たとえば、ボットがこのターンで応答を生成していない場合は、ボットが受信したすべてのメッセージ アクティビティをログに記録したり、フォールバック応答を提供したりできます。 ミドルウェアは、ボット ロジックの残りの部分が実行される前と後の両方で動作する機能を備えた、このようなプロセスに最適な場所です。
ターン コンテキストの変更または拡張
ボットがアクティビティで提供される情報よりも多くの情報を持っている場合、特定の会話の方がはるかに実りのあるものになる可能性があります。 この場合、ミドルウェアは、これまでに持っている会話状態情報を確認し、外部データ ソースにクエリを実行し、それを ターン コンテキスト オブジェクトに追加してから、ボット ロジックに実行を渡すことができます。
SDK では、受信アクティビティと送信アクティビティを記録できるログ ミドルウェアが定義されていますが、独自のミドルウェアを定義することもできます。
ボット ミドルウェア パイプライン
各アクティビティについて、アダプターはミドルウェアを追加した順序で呼び出します。 アダプターはターンと 次 のデリゲートのコンテキスト オブジェクトを渡し、ミドルウェアはデリゲートを呼び出して、パイプライン内の次のミドルウェアに制御を渡します。 ミドルウェアには、メソッドを完了する前に 、次 のデリゲートが戻った後に操作を行う機会もあります。 これは、各ミドルウェア オブジェクトが、パイプライン内でそれに続くミドルウェア オブジェクトに対して最初と最後に動作する機会を持つものとして考えることができます。
例えば次が挙げられます。
- 最初のミドルウェア オブジェクトのターン ハンドラーは、 次を呼び出す前にコードを実行します。
- 2 番目のミドルウェア オブジェクトのターン ハンドラーは、 次に呼び出す前にコードを実行します。
- ボットのターン ハンドラーが実行され、結果を返します。
- 2 番目のミドルウェア オブジェクトのターン ハンドラーは、戻る前に残りのコードを実行します。
- 2 番目のミドルウェア オブジェクトのターン ハンドラーは、 次に呼び出す前にコードを実行します。
- 最初のミドルウェア オブジェクトのターン ハンドラーは、戻る前に残りのコードを実行します。
ミドルウェアが次のデリゲートを呼び出さない場合、アダプターは後続のミドルウェアまたはボット ターン ハンドラーを呼び出せず、パイプラインのショートサーキットも呼び出しません。
ボット ミドルウェア パイプラインが完了すると、ターンが終了し、ターン コンテキストがスコープ外になります。
ミドルウェアまたはボットは応答を生成し、応答イベント ハンドラーを登録できますが、応答は個別のプロセスで処理されます。
ミドルウェアの順序
ミドルウェアが追加される順序によってミドルウェアがアクティビティを処理する順序が決まるため、ミドルウェアを追加するシーケンスを決定することが重要です。
注
これは、ほとんどのボットで動作する一般的なパターンを提供することを目的としていますが、各ミドルウェアが状況に合わせて他のミドルウェアと対話する方法を必ず考慮してください。
すべてのボットに最初にミドルウェア パイプラインに追加する必要がある最下位レベルのタスクを処理するミドルウェア。 たとえば、ログ記録、例外処理、翻訳などがあります。 メッセージを保存する前に受信メッセージを最初に翻訳するか、メッセージ ストレージを最初に行うかなど、ニーズに応じてこれらを並べ替えます。これは、保存されたメッセージが変換されない可能性があります。
ボット固有のミドルウェアは、最後にミドルウェア パイプラインに追加する必要があります。ミドルウェアは、ボットに送信されるすべてのメッセージに対して何らかの処理を実行するために実装します。 ミドルウェアがボット コンテキストで状態情報またはその他の情報セットを使用する場合は、状態またはコンテキストを変更するミドルウェアの後にミドルウェア パイプラインに追加します。
短絡
ミドルウェアと応答ハンドラーに関する重要な考え方は 、ショートサーキットです。 その後のレイヤーを実行し続ける場合、ミドルウェア (または応答ハンドラー) は、 次 のデリゲートを呼び出して実行を渡す必要があります。 次のデリゲートがそのミドルウェア (または応答ハンドラー) 内で呼び出されない場合、関連付けられているパイプラインのショートサーキットと後続のレイヤーは実行されません。 つまり、すべてのボット ロジックと、パイプラインに沿ったミドルウェアはスキップされます。 ミドルウェアと応答ハンドラーが処理を中断する際の差には微妙な違いがあります。
ミドルウェアがターンをショートする場合、ボット ターン ハンドラーは呼び出されませんが、パイプラインのこの時点より前に実行されたすべてのミドルウェア コードは、引き続き完了まで実行されます。
イベント ハンドラーの場合、 next を呼び出さないということは、イベントが取り消されることを意味します。これはミドルウェアのスキップ ロジックとは大きく異なります。 残りのイベントを処理しないことで、アダプターはイベントを送信しません。
ヒント
SendActivitiesなどの応答イベントをショートサーキットする場合は、それが意図した動作であることを確認してください。 そうしないと、バグの修正が困難になることがあります。
応答イベント処理装置
アプリケーションとミドルウェアのロジックに加えて、応答ハンドラー (イベント ハンドラーまたはアクティビティ イベント ハンドラーとも呼ばれます) をコンテキスト オブジェクトに追加できます。 これらのハンドラーは、実際の応答を実行する前に、現在のコンテキスト オブジェクトで関連する応答が発生したときに呼び出されます。 これらのハンドラーは、現在の応答の残りの部分で、その型のすべてのアクティビティについて、実際のイベントの前または後に何かを行う必要があることがわかっている場合に便利です。
Warnung
それぞれの応答イベント ハンドラー内からアクティビティ応答メソッドを呼び出さないように注意してください。たとえば、送信時アクティビティ ハンドラー内から送信アクティビティ メソッドを呼び出します。 これを行うと、無限ループが生成される可能性があります。
新しいアクティビティごとに、実行する新しいスレッドが取得されます。 アクティビティを処理するスレッドが作成されると、そのアクティビティのハンドラーの一覧がその新しいスレッドにコピーされます。 そのポイントの後に追加されたハンドラーは、その特定のアクティビティ イベントに対して実行されません。 コンテキスト オブジェクトに登録されたハンドラーは、アダプターがミドルウェア パイプラインを管理する方法と同様に処理されます。 つまり、ハンドラーは追加された順序で呼び出され、次のデリゲートを呼び出すと、次に登録されたイベント ハンドラーに制御が渡されます。 ハンドラーが次のデリゲートを呼び出さない場合、後続のイベント ハンドラーは呼び出されません。イベントショートサーキットが発生し、アダプターはチャネルに応答を送信しません。
ミドルウェアでの状態の処理
状態を保存する一般的なメソッドは、ターン ハンドラーの末尾で save changes メソッドを呼び出す方法です。 呼び出しに焦点を当てた図を以下に示します。
このアプローチの問題は、ボットのターン ハンドラーが返された後に発生する一部のカスタム ミドルウェアから行われた状態の更新は、永続的なストレージに保存されないということです。 解決策は、変更の自動保存ミドルウェアのインスタンスをミドルウェア スタックの先頭に追加するか、少なくとも状態を更新する可能性のあるミドルウェアの前に追加することで、カスタム ミドルウェアが完了した後に、 save changes メソッドへの呼び出しを移動することです。 実行を次に示します。
ボット状態セット オブジェクトに更新する必要がある状態管理オブジェクトを追加し、自動保存変更ミドルウェアを作成するときにそれを使用します。
その他のリソース
Bot Framework SDK [C# | JS] に実装されているトランスクリプト ロガー ミドルウェアを確認できます。