Microsoft Botframework + Adaptive Cards 快速打造 Chatbot 之 2

前言

在 Microsoft Botframework + Adaptive Cards 快速打造 Chatbot 一篇中,
我們說明如何透過 Adaptive Cards 將所有的動作透過 Action 再依它的 Action Type 來轉換成對應的 Action 物件及處理該 Action 物件的 Strategy 物件。

但是當我們的 Action 逾來逾多時,原本使用 switch 勢必會造成相對應的複雜度,依 Strategy 的方式是建立對應表,以下將介紹使用 Dictionary<string, Func<T>> 及 Autofac DI 這2種方式。

另外,如果 Strategy 物件 中有使用到 Prompt dialogs 時,原本在執行完 Strategy 物件的 Method 後,如果直接呼叫 context.Done(“”); 將會造成 botframework Dialog Stack 運行上的錯誤,我們也將修改 Strategy 物件實作的 interface ,增加最後是否要自動執行 context.Done 。 繼續閱讀 “Microsoft Botframework + Adaptive Cards 快速打造 Chatbot 之 2”

使用SqlBulkCopy做資料轉檔

bcp( sqlbulkcopy ) 原本是命令列上的工具,用來做大量複製資料的工作。
在.NET裡面也可以調用他的功能。

SqlBulkCopy 類別可用於僅將資料寫入 SQL Server 資料表。 但是資料來源不僅限於 SQL Server;可使用任何資料來源,只要該資料可載入 DataTable 執行個體,或可使用 IDataReader 執行個體進行讀取。 M$ docs 

這次我們使用他來做資料表的轉檔,將會有準備資料與執行兩部分。

繼續閱讀 “使用SqlBulkCopy做資料轉檔”

Microsoft Botframework + Adaptive Cards 快速打造 Chatbot

前言

今年的 Chatbot 很火紅,不知大家都用什麼來開發 Chatbot 呢?
筆者使用的是 Microsoft Botframework 來開發,它提供了很多語言的 SDK,讓我們可以快速的開發出 Chatbot。
最近開發 Vitals ESP (KM) Chatbot,一開始規劃好畫面及流程後,很快就開發完成了。
接下來就跟大家分享開發的過程 🙂

需求

Vitals ESP 是 KM 系統,希望 KM Chatbot 可以方便讓人查詢,在手機上畫面不大,所以需要分頁。如果有人 Mention 到你的話,也可以發通知到 Chatbot 上,讓你可以快速地回覆。
所以需求主要有 2 個,

繼續閱讀 “Microsoft Botframework + Adaptive Cards 快速打造 Chatbot”

IBotDataStore.FlushAsync Exception: The data is changed

前言

最新有個需求就是要判斷目前 User 是不是在進行某項作業, 如果不是就推送包含 Button 的訊息給 User, 不然就推文字通知訊息等目前的作業完成後,再顯示待辦的 Button 訊息給 User .

研究

最簡單的就是將這個 flag 寫在 BotState 之中,所以我們可以在使用者加入時,將它的 Conversation 記錄下來,如下,

if (message.Type == ActivityTypes.ConversationUpdate)
{
Func<ChannelAccount, bool> isChatbot =
channelAcct => channelAcct.Id == message.Recipient.Id;
if (message.MembersAdded.Any(isChatbot))
{
var memberAdded = message.MembersAdded.FirstOrDefault();
//這裡請自行處理將該 user 的 Conversation 儲存起來,為了方便,這裡將它存在一個變數之中
WebApiApplication._ConversationReference = message.ToConversationReference();
}
}

然後在申請作業記錄這個 Flag ,當然,結束時請記得將這個 Flag 清除哦!

using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, context.Activity.AsMessageActivity()))
{
var botDataStore = scope.Resolve<IBotDataStore<BotData>>();
var key = Address.FromActivity(context.Activity);
var botUserData = await botDataStore.LoadAsync(key, BotStoreType.BotUserData, default(CancellationToken));
botUserData.SetProperty<string>(“dialog”, “RootDialog:MessageReceivedAsync”);
await botDataStore.SaveAsync(key, BotStoreType.BotUserData, botUserData, default(CancellationToken));
await botDataStore.FlushAsync(key, default(CancellationToken));
}

可是執行時,卻發生了「Exception: The data is changed」的錯誤,如下圖,
[Exception: The data is changed]

因為 botframework 會自動去幫我們將 State 存檔,所以當它存檔時,發現狀態被改掉了,所以就出現「Exception: The data is changed」的錯誤 .

嗯, 那怎麼辦呢? 那就調整程式, 不要去呼叫 FlushAsync, 讓 botframework 去存就可以了, 所以程式調整如下,

using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, context.Activity.AsMessageActivity()))
{
var botDataStore = scope.Resolve<IBotDataStore<BotData>>();
var key = Address.FromActivity(context.Activity);
var botUserData = await botDataStore.LoadAsync(key, BotStoreType.BotUserData, default(CancellationToken));
botUserData.SetProperty<string>(“dialog”, “RootDialog:MessageReceivedAsync”);
await botDataStore.SaveAsync(key, BotStoreType.BotUserData, botUserData, default(CancellationToken));
//await botDataStore.FlushAsync(key, default(CancellationToken));
}

所以我們的通知程式就可以透過 ConversationReference 轉回 Activity, 取回 BotState, 例如,我新增一個 api method 來顯示 BotState , 如下,

[Route(“api/Messages/GetDialogData”)]
[HttpGet]
public async Task<HttpResponseMessage> GetDialogData()
{
var resp = new HttpResponseMessage(HttpStatusCode.OK);
if (WebApiApplication._ConversationReference != null)
{
var message = WebApiApplication._ConversationReference.GetPostToBotMessage();
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message.AsMessageActivity()))
{
var botDataStore = scope.Resolve<IBotDataStore<BotData>>();
var key = Address.FromActivity(message);
var botUserData = await botDataStore.LoadAsync(key, BotStoreType.BotUserData, default(CancellationToken));
var dialogData = botUserData.GetProperty<string>(“dialog”);
resp.Content = new StringContent($”<html><body>Dialogs:{dialogData}</body></html>”, System.Text.Encoding.UTF8, @”text/html”);
}
}
return resp;
}

所以在 Dialog 中儲存 State 時 , 可以注意一下這種狀況哦 ^_^

Demo 專案可以參考 rainmakerho/Exception_DataChanged

參考資料

Microsoft Bot Framework: Exception: The data is changed

Asp.Net MVC Model Validation:Custom Validation – 以 Required If 為例

在前篇「Asp.Net MVC Model Validation:Remote validation」的介紹之下,想必大家對於 .Net MVC 的 Model Validation 運作機制都有一定程度的了解,接下來將進一步介紹如何在 .Net MVC Model Validation 的運作機制加上自訂驗證規則(前、後端,使我們專案的表單驗證機制更加完善

繼續閱讀 “Asp.Net MVC Model Validation:Custom Validation – 以 Required If 為例”