前言
在 Microsoft Botframework + Adaptive Cards 快速打造 Chatbot 一篇中,
我們說明如何透過 Adaptive Cards 將所有的動作透過 Action 再依它的 Action Type 來轉換成對應的 Action 物件及處理該 Action 物件的 Strategy 物件。
但是當我們的 Action 逾來逾多時,原本使用 switch 勢必會造成相對應的複雜度,依 Strategy 的方式是建立對應表,以下將介紹使用 Dictionary<string, Func<T>> 及 Autofac 這2種方式。
另外,如果 Strategy 物件 中有使用到 Prompt dialogs 時,原本在執行完 Strategy 物件的 Method 後,如果直接呼叫 context.Done(“”); 將會造成 botframework Dialog Stack 運行上的錯誤,我們也將修正 Strategy 物件的 interface 。
實作
調整 Strategy 物件的建立方式
因為對應的 Strategy 物件變成了4個,如果用 switch 判斷的話,程式如下,
1 | /// <summary> |
因為 botframework 已使用 Autofac ,所以我們可以透過 Autofac Named Services 方式來建立對應表,所以在 ActionStrategyResolver 物件中建立 ResolveByActionTypes Method 然後在 Global.asax.cs Application_Start Method 中去呼叫 ResolveByActionTypes Method。如下,
1 | /// <summary> |
而在取得對應的 Strategy 物件時,只要給 Action Type 值 ( var actionStrategy =scope.ResolveNamed
1 | /// <summary> |
調整 Action 物件的建立方式
之前在 JsonConverter 中依 ActionType 透過 switch 來建立物件,我們可以建立一個 Dictionary 來對應生成的Function,因為會需要 jtoken 所以建立的 Dictionary為,Dictionary<string, Func<JToken, BotAction>> ,然後在 static construct 時建立它 (ActionConverter是我們的 class name),如下,
1 | // 設定依 ActionType 來建立物件的 Dictionary |
所以原本在 ReadJson Method 裡面的 switch 改成依 ActionType 當成 BotActionMapper 的 Key ,取出生成的 Function ,然後呼叫它( BotAction result = BotActionMappertype.ToString(); ),
如下,
1 | /// <summary> |
設定是否呼叫 context.Done(“”)
之前我們執行完 Strategy 物件的 Method 後,會直接呼叫 context.Done(“”) ,這表示這個 Strategy 物件的事已做好了,再進來的訊息又是會對應到新的 Strategy 物件。
但有時,Strategy 物件會需要再從使用者那取得回應,例如用了 PromptDialog 相關的 Method, 它需要傳入一個 resume 的 Callback Function,在整個結束才會呼叫 contex.Done(“”),所以這時候,就不可以直接呼叫 context.Done 。
所以 Strategy 物件的 interface 多加入一個設定是否呼叫 contex.Done(“”) 的屬性,或是改成不呼叫,全都交由 Strategy 物件自行決定。如下,
1 | /// <summary> |
所以在上面的 DoActionAsync 有依 IsContextDone 屬性來判斷是否執行 contex.Done(“”) 。
經過將 switch 改以 Dictionary or Autofac DI 方式來建立物件,改善了複雜度,也提升了可讀性。
另外在使用 contex.Done 的時機點,大家也要注意一下哦 :)
希望對大家以 Microsoft Botframework 來開發 Chatbot 有所幫助。
參考資料
Microsoft Botframework + Adaptive Cards 快速打造 Chatbot
Strategy
Autofac Named Services