在上一篇([07]Dialog - 控制流程的元件介紹)介紹了Dialog的原件之後,接下來就是要實際使用看看是什麽感覺。
這篇先用最基本的TextPrompt
,看看如何簡化詢問姓名的邏輯。
修改方式
還記得之前上一篇提到了關於Dialog會被放在在DialogSet
裡面,然後由Bot執行啓動。
DialogSet
會需要State Accessor用來記錄執行過程的一些信息。
有了這些概念之後,接下來的調整就是:
- 安裝Dialog的package套件
- 建立出一個
DialogState
的Accessor - 調整
Startup
初始化Accessor - 建立出
DialogSet
以及TextPrompt
- 測試
安裝Dialog的package套件
Dialog是一個額外的套件,因此要使用需要額外安裝套件,可以透過Package Management Console執行: Install-Package Microsoft.Bot.Builder.Dialogs
安裝了之後,要使用的地方需要加入using Microsoft.Bot.Builder.Dialogs;
建立出一個DialogState的Accessor
打開EchoBotAccessors.cs
并且增加:
public class EchoBotAccessors
{
...
public static string DialogStateName { get; } =
$"{nameof(EchoBotAccessors)}.DialogState";
public IStatePropertyAccessor<DialogState> DialogState { get; set; }
...
}
再來就是要new這個Accessor啦。
調整Startup初始化Accessor
再來切換到Startup.cs
,這個時候在設定EchoBotAccessor
的時候,要增加一段:
services.AddSingleton<EchoBotAccessors>(sp =>
{
var accessors = new EchoBotAccessors
(conversationState, userState)
{
....
DialogState = conversationState.CreateProperty<DialogState>
(EchoBotAccessors.DialogStateName)
};
return accessors;
}
這樣Accessor的部分就準備好了。
建立出DialogSet以及TextPrompt
再來打開EchoWithCounterBot.cs
,準備修改邏輯。
首先是Constructor的部分:
public class EchoWithCounterBot : IBot
{
...
private readonly DialogSet _dialogs;
public EchoWithCounterBot(EchoBotAccessors accessors,
ILoggerFactory loggerFactory)
{
....
_dialogs = new DialogSet(_accessors.DialogState);
_dialogs.Add(new TextPrompt("askName"));
}
}
這邊建立出一個DialogSet
,并且在這個DialogSet增加了一個TextPrompt
叫做askName
。
再來調整OnTurnAsync
的邏輯:
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
if (turnContext.Activity.Type == ActivityTypes.Message)
{
var state = await _accessors.CounterState.GetAsync
(turnContext, () => new CounterState());
var userInfo = await _accessors.UserInfo.GetAsync
(turnContext, () => new Model.UserInfo());
var dialogContext = await _dialogs.CreateContextAsync
(turnContext, cancellationToken);
var dialogResult = await dialogContext.ContinueDialogAsync
(cancellationToken);
if (string.IsNullOrEmpty(userInfo.Name)
&& dialogResult.Status == DialogTurnStatus.Empty)
{
await dialogContext.PromptAsync(
"askName",
new PromptOptions
{ Prompt = MessageFactory.Text("請問尊姓大名?") },
cancellationToken);
}
else if(dialogResult.Status == DialogTurnStatus.Complete)
{
if (dialogResult.Result != null)
{
userInfo.Name = dialogResult.Result.ToString();
await _accessors.UserInfo.SetAsync(turnContext, userInfo);
await _accessors.UserState.SaveChangesAsync(turnContext);
await turnContext.SendActivityAsync($"{userInfo.Name} 您好");
}
}
else
{
// 原本的EchoBot邏輯
}
}
else
{
.....
}
await _accessors.ConversationState.SaveChangesAsync(turnContext);
}
測試
上面修改完成之後,接下來就是測試的時候啦。
從這邊會發現,整個操作感覺和之前沒有差。
結語
這篇把原本自己管理的ConversationState,改成使用TextPrompt
來管理。
從結果來説,兩邊的結果是一致的,但是從程式碼的角度來説其實沒什麽太大差異。
就算用了TextPrompt
好像和自己管理沒什麽差,那爲什麽要用呢?
原因是目前的例子太簡單了,下一篇([09]使用waterfall建立表單式填寫)把問題用複雜一點,看看搭配waterfall的dialog整體使用感覺如何。