Bot Framework と Microsoft Graph で DevOps その 13 : グローバルメッセージでダイアログを制御

※2017/6/10 テストについてやっぱり追記 今回はグローバルメッセージについて紹介します。 概要 ユーザーは開発者の意図通りに話してくれるか分からないという話は既にしました。途中でキャンセルしたいかもしれないし、急遽別のことを確認したいかもしれません。そのような場合は、特定のキーワードで現在の処理を中断したりキャンセルできるようにします。Bot Framework ではこのような処理またはキーワードをグローバルメッセージと呼んでいます。 処理のキャンセル 1. まずキャンセルのキーワードを登録。ボットアプリプロジェクトの Dialogs フォルダに、CancelScorable.cs を作成し、以下のコードと差し替えます。キーワードは多言語対応ということでリソースを使っています。 using System; using System.Threading; using System.Threading.Tasks; using Microsoft.Bot.Builder.Dialogs.Internals; using Microsoft.Bot.Builder.Internals.Fibers; using Microsoft.Bot.Connector; using Microsoft.Bot.Builder.Scorables.Internals; using O365Bot.Resources; namespace O365Bot.Dialogs { #pragma warning disable 1998     public class CancelScorable : ScorableBase<IActivity, string, double>     {         private readonly IDialogTask task;         public CancelScorable(IDialogTask task)… Read more

Bot Framework と Microsoft Graph で DevOps その 12 : ボットアプリとテストの多言語対応

※2017/6/10 ユニットテストとファンクションテストのコードを修正。 今回はこれまで紹介したダイアログやフォームフローにも関係する、多言語対応について紹介します。 Activity の Locale プロパティ Web API に送られてくる Activity には Locale プロパティがあります。ダイアログやフォームフローで作成されたダイアログはこの値をみて、動的に言語を切り替えます。ただすべてのチャネルで Locale セットしてくれるわけではありません。またダイアログ以外の独自のラベルは、別途多言語対応する必要があります。 エミュレーターでの言語指定 言語を接続時に指定できます。 多言語対応 リソースファイル ボットアプリはただの Web API のため、resx ファイルを使った多言語対応が可能です。 1. ボットアプリプロジェクトに Resources フォルダを追加。 2. 新しいアイテムとしてリソースファイルを追加。名前は O365BotLabel.resx としました。これが既定の言語リソースになります。 3. Create_Event を追加し、値として Creating an event. と設定。 4. 次に同じフォルダ内に、O365BotLabel.ja.resx リソースファイルを追加。以下のように同じリソースを追加。 5. CreateEventDialog.cs を開いて、コードを差し替え。ハードコードされたコメントをリソースに入れ替えました。また BuildOutlookEventForm を public static にしています。 using Autofac; using Microsoft.Bot.Builder.Dialogs;… Read more

Bot Framework と Microsoft Graph で DevOps その 11 : フォームフロー応用編

前回はフォームフローの概要を紹介しました。今回はフォームフローの高度な使い方を見ていきます。 FormBuilder 前回は以下のコードを使ってクラスからダイアログを自動生成しました。 return new FormBuilder<OutlookEvent>()     .Message(“イベントを作成します。”)     .AddRemainingFields() // すべてのフィールドを処理対象として追加     .OnCompletion(processOutlookEventCreate)     .Build(); FormBuilder は様々な機能がありますが、上記の例では AddRemainingFields メソッドで、クラスのすべてのフィールドをダイアログに追加、OnCompletion メソッドで完了時の処理呼び出しをしています。プロンプトの情報はクラスのプロパティに定義した Prompt や Template 属性から情報を得ています。 [Prompt(“件名は?”)] public string Subject { get; set; } 以下で他の機能を見ていきます。 個別にフィールド追加 Field メソッドを使うことで、個別にフィールドが追加できます。例えば以下の場合は件名と詳細だけを含めています。 return new FormBuilder<OutlookEvent>()     .Message(“イベントを作成します。”)     .Field(nameof(OutlookEvent.Subject))     .Field(nameof(OutlookEvent.Description))     .OnCompletion(processOutlookEventCreate)     .Build(); Field メソッドは個別にフィールドを追加するだけでなく、プロンプトの指定、表示するかどうかの検証、入力した値の検証などを含めることが出来ます。 return new FormBuilder<OutlookEvent>()… Read more

Bot Framework と Microsoft Graph で DevOps その 10 : フォームフロー入門編

前回はダイアログ応用編として DialogPrompt の機能など紹介しました。今回はフォームフロー (FormFlow) 入門編をお届けします。 概要 前回 DialogPrompt を利用して、イベント作成に必要な情報を集めました。しかしフォームフローはこれをさらに簡単にしてくれます。フォームフローはクラスの定義を元に、適切なダイアログを作ってくれます。百読は一コードに如かずということで早速。 フォームフローを利用したイベントの作成 モデルの作成 フォームフローはモデルベースであるため、モデルを作ります。Microsoft.Graph.Event クラスをそのままモデルに使いたいんですが、Serializable 属性ないんですよね。あと不要なフィールドなどもあるので、新規作成を。 1. Visual Studio でボットアプリプロジェクトに Models フォルダを追加。 2. Models フォルダ内に、OutlookEvent.cs を追加し、以下と差し替え。Serializable 属性忘れないように。 using System; namespace O365Bot.Models {     [Serializable]     public class OutlookEvent     {         public string Subject { get; set; }         public string Description { get; set; }        … Read more

Bot Framework と Microsoft Graph で DevOps その 9 : ダイアログ応用編

※ 2017/6/10 ファンクションテスト修正 前回はダイアログ入門編として基礎を紹介しました。今回はイベント (予定) の追加を実装し、その中で応用編としてダイアログの便利な機能を紹介します。 DialogPrompt ボットアプリがユーザーと会話を行う際に、開発者は以下の点を考慮する必要があります。 ユーザーに返信する内容: 単純なテキストか、ボタンなどよりリッチなコンテンツか。 ユーザー入力の検証。数値や日付を期待している場合に、意図したものが返ってきたか。 意図しないものが返った場合のリトライ処理と文言の変更。 リトライしてもダメだった場合の処理。 他にも色々ありますが、DialogPrompt を使えば上記のことは簡単に処理できます。また DialogPrompt は多言語に対応しており、Activity の Locale を設定すれば自動的に任意の言語になります。開発者が指定するメッセージの多言語化はまたの機会に。 イベント追加機能の実装 GraphService の変更 1. IEventService.cs にイベントを作成するメソッドを追加。 public interface IEventService {     Task<List<Event>> GetEvents();     Task CreateEvent(Event @event); } 2. 実体である GraphService.cs もイベントを作る部分を追加します。 public async Task CreateEvent(Event @event) {     var client = await GetClient();            … Read more

Bot Framework と Microsoft Graph で DevOps その 8 : ダイアログ入門編

前回までで DevOps に必要な最低限の環境は整えました。今回から BotBuilder を深く。まずはダイアログ (Dialog) の入門編から。 ダイアログの概念 高度なボットはユーザーと会話することが必要です。つまり、ユーザーが言ったことを覚え、適切に次のアクションをとる必要があります。これ実装するのは結構骨なんですが、BotBuilder の Dialog 機能を使うと、とても簡単に実装ができます。通常 ダイアログは機能単位で分割して実装します。以下に本家の記事を引用して説明します。 引用元: https://docs.microsoft.com/ja-jp/bot-framework/bot-design-conversation-flow 以下の絵は通常のアプリとボットアプリの対比を示したもので、新しいオーダーから製品を探すフローを示しています。 通常アプリはメイン画面が起動。そこからオーダー画面を起動した場合、明示的に閉じられるか処理が完了するま画面はそのままです。一方ボットの場合は全てがルートダイアログから始まり、そこから オーダーダイアログが起動されると会話を引き継ぎ、明示的に中断されるか処理が完了すると ルートダイアログに処理が戻ります。 ダイアログのスタックと実際のユーザーの相違 ユーザーが開発者の意図通りに、ダイアログを順次実行するとは限らず、気分や状況で返事してきます。例えば。。 このようにボットアプリが予約を確定しようとしている段階で、「その映画何時だったかな?」と聞いてきたりします。この場合、以下のような処理が考えられます。 – ユーザーに、まず回答するように促す。 – これまでの処理をすべて破棄して、ユーザーの質問に回答する。 – ユーザーの質問に回答して、確認に戻る。 正確はなく、ユーザーシナリオやボットアプリに対する期待値によって解決策は変わります。 まぁ個人的には 3 つ目がいいですが。。 C# でのダイアログ実装 概念がわかったところで実装を。 RootDialog の実行 ボットアプリの実体はただの Web API で、常に MessagesController の Post メソッドにリクエストがきます。そこから Root Dialog を実行します。テンプレ通りです。 MessagesController.cs public async Task<HttpResponseMessage> Post([FromBody]Activity activity) {… Read more

Bot Framework と Microsoft Graph で DevOps その 7 : リリース定義の作成

※2017/6/10 アプリリリース定義の手順 6 画面ショット差し替え。テストアセンブリの指定が間違っていました。 前回はファンクションテストを実装しました。今回は VSTS でリリース定義を作成します。 リリース定義とは リリース定義はコンパイルしたモジュールを App Service などに公開する用途で使います。今回は以下の 3 つをやります。 – Infrastructure as a Code (Azure の場合は ARM テンプレート) を使って環境を自動整備 – リリース – ファンクションテスト ARM テンプレートの詳細はこちら ※今回の作業を始める前に、前回のファンクションテストチェックインした後に、ビルドが完了していることを確認しておいてください。 Azure Resource Manager テンプレート 前回手動で Azure App Services にアプリを公開しました。今回はこれをテンプレート化して自動的に行えるようにします。 テンプレートの取得 1. https://portal.azure.com にログイン。一旦前回作成したリソースグループを削除。 2. 新規から Web App を選択。 3. 各種設定を行い、作成ボタンが出るところまで進め、Create の横にある Automation options をクリック。 4. Download… Read more

Bot Framework と Microsoft Graph で DevOps その 6 : ファンクションテストのセットアップ

※この記事書いてて、前に出した記事のコード間違っていることに気づきました。すでに見てコピペした人は直してください。 前回はビルド定義まで作りました。今回はファンクションテストについて考えます。ちょっと長いです。 Bot Framework でのファンクションテスト Bot Framework では、Direct Line を使って通しのテストができます。しかし Bot Connector が特定の URL しか見ないので、テスト用のボットアプリも登録する必要があります。Infrastructure as a Code については次回。 Azure App Services へアプリを公開 1. ボットアプリプロジェクトを右クリックして Publish。 2. Microsoft Azure App Services を選択し、新規作成。 3. まず本番用に作成して、公開。 4. 公開が終わったら、Create new profile リンクから、もう 1 つプロファイルを作成。 5. テスト用に公開。別に同じリソースグループやサービスプランである必要はありません。 ボットアプリの登録 1. https://dev.botframework.com に行って、サインイン。 2. My Bots より Create a bot をクリック。… Read more

Bot Framework と Microsoft Graph で DevOps その 5 : VSTS で Continuous Integration

※2017/6/10 ファイルコピータスクの追加手順を忘れていたので追加。これないとファンクションテスト動きません。。。 前回は依存サービスをモック化しました。今回は VSTS で CI (Continuous Integration) を設定します。 とりあえずコードチェックインの確認 1. VSTS にログインして、今回用のプロジェクトを開きます。Visual Studio のチームエクスプローラーからも、ワンクリックで移動できます。 2. Code 項目でこれまでのコードがチェックインされていることを確認。 ビルド定義の作成とテスト実行 コードをチェックインするたびに、コンパイルしてテストを実行できるように、ビルド定義を作ります。 1. Build & Release タブより Builds を選択。「New definition」をクリック。 2. テンプレートより ASP.NET を選択。 3. 名前を適当に変更。 4. Get sources 項目から、正しいソースが選択されているか確認。ソース管理に GitHub 等も使えます。 5. Test Assemblies を選択し、Test assemblies の項目を変更。今回のユニットテストのライブラリは O365Bot.UnitTests.dll なので合わせました。 6. その他のオプションも必要に応じて変更。ここではコードカバレッジをチェック。 7. Add Task をクリック。 8…. Read more

Bot Framework と Microsoft Graph で DevOps その 4 : Microsoft Fakes, AutoFac, Moq で依存サービスのモック化

前回は AuthBot と Microsoft Graph を呼べるようにしました。今回は変更したものをユニットテストしてみます。 依存サービスのモック 依存サービスはモックを作り、常に意図した動作をするようにすることで、本当にテストしたい部分のユニットテストを行います。AuthBot と GraphService それぞれモック化します。 AuthBot のモック化 コード内で AuthBot の GetAccessToken メソッドを実行して、OAuth 2.0 のアクセストークンを取得していますが、ここをモック化します。ソースコードを見ると GetAccessToken は静的な部分メソッドですので、Microsoft Fakes を使います。Fakes の詳細はこちら。 1. Fake アセンブリを作るため、ユニットテストプロジェクトにも AuthBot を追加して、各種 NuGet パッケージを最新に更新します。 2. AuthBot 参照を右クリックして、Fakes Assembly を追加します。 3. UnitTest1.cs の ShouldReturnCount メソッドを削除して、以下のように書き換えます。 [TestMethod] public async Task ShouldReturnEvents() {     // Fakes を使うためにコンテキストを作成     using (ShimsContext.Create())… Read more