上一篇文章講了activity處理的流程,我們bot的核心處理邏輯放在ActivityHandler的子類里,通過重載OnMessageActivityAsync()
方法來實現。
這篇文章我來講一下對于Teams的bot來說,整個處理的邏輯會有哪些不同點。
通過之前的文章,大家應該已經知道,Teams bot是Azure bot service支持的眾多bot聊天平臺里的一種channel(注意:這里的channel指bot service里的channel,和Teams里的channel是完全不同的概念)。但是Teams實際上提供了很多特有的事件和動作。使用bot sdk的通用模型,我們當然可以處理這些事情,但是Teams作為微軟的主打產品,微軟的bot sdk當然要為它提供更多的開發便利性。
SDK提供了一個針對Teams的ActivityHandler。這個handler有下面這些特殊的ConversationUpdateActivity的處理函數
事件 | 函數 | 說明 |
---|---|---|
channelCreated | OnTeamsChannelCreatedAsync | 當Teams的channel被創建 |
channelDeleted | OnTeamsChannelDeletedAsync | 當Teams的channel被刪除 |
channelRenamed | OnTeamsChannelRenamedAsync | 當Teams的channel被重命名 |
teamRenamed | OnTeamsTeamRenamedAsync | 當Teams的一個team被重命名 |
MembersAdded | OnTeamsMembersAddedAsync | 當Teams的一個team中有新用戶加入 |
MembersRemoved | OnTeamsMembersRemovedAsync | 當Teams的一個team中有用戶被移除 |
除了ConversationUpdateActivity這些Teams的特殊事件,handler還提供了一些Teams特有的invoke動作的處理
Invoke類型 | 函數 | 說明 |
---|---|---|
CardAction.Invoke | OnTeamsCardActionInvokeAsync | 關于卡片的動作,比如卡片上一個按鈕被點擊了 |
fileConsent/invoke | OnTeamsFileConsentAcceptAsync | 用戶同意了上傳文件 |
fileConsent/invoke | OnTeamsFileConsentAsync | 用戶要上傳文件. |
fileConsent/invoke | OnTeamsFileConsentDeclineAsync | 用戶拒絕了上傳文件. |
actionableMessage/executeAction | OnTeamsO365ConnectorCardActionAsync | O365連接器的卡片動作 |
signin/verifyState | OnTeamsSigninVerifyStateAsync | 登入驗證狀態 |
task/fetch | OnTeamsTaskModuleFetchAsync | Teams的Task Module的獲取 |
task/submit | OnTeamsTaskModuleSubmitAsync | Teams的Task Module的提交 |
上面表格中的OnTeamsFileConsentAsync
實際上是OnTeamsFileConsentAcceptAsync
和OnTeamsFileConsentDeclineAsync
的一個綜合處理,你可以重載OnTeamsFileConsentAsync
,或者分別重載 accept 和 decline 函數。下面的sdk代碼可以讓你有直觀的了解
protected virtual async Task<InvokeResponse> OnTeamsFileConsentAsync(ITurnContext<IInvokeActivity> turnContext, FileConsentCardResponse fileConsentCardResponse, CancellationToken cancellationToken)
{switch (fileConsentCardResponse.Action){case "accept":await OnTeamsFileConsentAcceptAsync(turnContext, fileConsentCardResponse, cancellationToken).ConfigureAwait(false);return CreateInvokeResponse();case "decline":await OnTeamsFileConsentDeclineAsync(turnContext, fileConsentCardResponse, cancellationToken).ConfigureAwait(false);return CreateInvokeResponse();default:throw new InvokeResponseException(HttpStatusCode.BadRequest, $"{fileConsentCardResponse.Action} is not a supported Action.");}
}
對于喜歡把問題研究透徹的朋友可能會問,Teams的ActivityHandler到底是怎么處理的?讓我們跳入sdk源代碼一探究竟。
public class TeamsActivityHandler : ActivityHandler
{protected override async Task<InvokeResponse> OnInvokeActivityAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken){...switch (turnContext.Activity.Name){case "fileConsent/invoke":return await OnTeamsFileConsentAsync(turnContext, SafeCast<FileConsentCardResponse>(turnContext.Activity.Value), cancellationToken).ConfigureAwait(false);case "task/fetch":return CreateInvokeResponse(await OnTeamsTaskModuleFetchAsync(turnContext, SafeCast<TaskModuleRequest>(turnContext.Activity.Value), cancellationToken).ConfigureAwait(false));case "task/submit":return CreateInvokeResponse(await OnTeamsTaskModuleSubmitAsync(turnContext, SafeCast<TaskModuleRequest>(turnContext.Activity.Value), cancellationToken).ConfigureAwait(false));......default:return await base.OnInvokeActivityAsync(turnContext, cancellationToken).ConfigureAwait(false);}...}protected override Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken){...switch (channelData.EventType){case "channelCreated":return OnTeamsChannelCreatedAsync(channelData.Channel, channelData.Team, turnContext, cancellationToken);case "channelDeleted":return OnTeamsChannelDeletedAsync(channelData.Channel, channelData.Team, turnContext, cancellationToken);case "channelRenamed":return OnTeamsChannelRenamedAsync(channelData.Channel, channelData.Team, turnContext, cancellationToken);case "teamRenamed":return OnTeamsTeamRenamedAsync(channelData.Team, turnContext, cancellationToken);default:return base.OnConversationUpdateActivityAsync(turnContext, cancellationToken);}...}
}
從上面的代碼里可以看到沒有什么特別的magic,TeamsActivityHandler重載了OnConversationUpdateActivityAsync
,并且根據channelData.EventType
判斷出不同teams的事件,然后調用相應的方法。對于invoke也類似,重載了OnInvokeActivityAsync
,根據turnContext.Activity.Name來調用不同的方法。
回到我們的EchoBot代碼,讓EchoBot從TeamsActivityHandler
繼承下來,然后我們可以添加OnTeamsChannelRenamedAsync
方法。把EchoBot設置到Teams里,修改安裝了EchoBot的channel的名字,就可以看到這個方法被促發的。
public class EchoBot : TeamsActivityHandler
{protected virtual Task OnTeamsChannelRenamedAsync(ChannelInfo channelInfo, TeamInfo teamInfo, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken){var replyText = "Channel renamed.";await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);}
}