天天看點

Teams Bot開發系列:Activity處理流程

上篇文章介紹了什麼是Activity,Turn,TurnContext和BotAdapter,這篇文章我們看看這些東西是如何竄起來的,他們是如何處理使用者發給bot的消息的。

我們以一個最簡單的bot,echo bot為例子,所謂的echo bot就是使用者發什麼消息,它就照樣回複一條消息。為了簡單起見,大家可以先安裝VS2019的一個擴充插件BotBuilderVSIX.vsix template,然後建立一個NET core 3.1的Echo bot。

Teams Bot開發系列:Activity處理流程

可以看到這個模闆為什麼建立了一個項目,我們先到Startup.cs看一下:

// Create the Bot Framework Adapter with error handling enabled.
services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

// Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
services.AddTransient<IBot, EchoBot>();
           

可以看到DI了兩個類,值得注意的是,

AdapterWithErrorHandler

使用的是Singleton,而

EchoBot

使用的是Transient,如果大家不同模闆來生成的話,這兩個千萬不能寫錯,不然會出意想不到的錯誤,而且非常難查。

打開

AdapterWithErrorHandler.cs

檔案,可以看到它從

BotFrameworkHttpAdapter

繼承下來。主要是提供了一些針對異常錯誤的處理

public class AdapterWithErrorHandler : BotFrameworkHttpAdapter
{
    public AdapterWithErrorHandler(IConfiguration configuration, ILogger<BotFrameworkHttpAdapter> logger)
        : base(configuration, logger)
    {
        OnTurnError = async (turnContext, exception) =>
        {
            ...
        };
    }
}
           

從bot sdk的源代碼裡,我可以知道 

BotFrameworkHttpAdapter

 一層層往上,最終到達 

BotAdapter

public class BotFrameworkHttpAdapter : BotFrameworkHttpAdapterBase, IBotFrameworkHttpAdapter
{
    ...
}

public class BotFrameworkHttpAdapterBase : BotFrameworkAdapter, IStreamingActivityProcessor
{
    ...
}

public class BotFrameworkAdapter : BotAdapter, IAdapterIntegration, IExtendedUserTokenProvider, IConnectorClientBuilder
{
    ...
}

public abstract class BotAdapter
{
    ...
}
           

現在,我們結合下面這張圖來了解整個的處理過程。

Teams Bot開發系列:Activity處理流程
  1. 可以看到,當使用者發了一條文字消息 “Hi”,這個消息被發到我們bot服務的時候,我們調用Adapter的

    ProcessActivity

    方法。我們在

    BotController.cs

    可以看到這個。
[Route("api/messages")]
public class BotController : ControllerBase
{
    private readonly IBotFrameworkHttpAdapter Adapter;
    private readonly IBot Bot;

    public BotController(IBotFrameworkHttpAdapter adapter, IBot bot)
    {
        Adapter = adapter;
        Bot = bot;
    }

    [HttpPost, HttpGet]
    public async Task PostAsync()
    {
        await Adapter.ProcessAsync(Request, Response, Bot);
    }
}
           
  1. Adapter建立TurnContext後,調用bot上的OnTurn方法,但是生成的Echo bot裡并看不到OnTurn方法,我們先看一下

    EchoBot.cs

public class EchoBot : ActivityHandler
{
    protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
    {
        var replyText = $"Echo: {turnContext.Activity.Text}";
        await turnContext.SendActivityAsync(MessageFactory.Text(replyText, replyText), cancellationToken);
    }
}
           

可以看到我們的EchoBot從ActivityHandler繼承下來,我們檢視一下SDK的源代碼,可以發現:

public class ActivityHandler : IBot
{
    public virtual async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        switch (turnContext.Activity.Type)
        {
            case ActivityTypes.Message:
                await OnMessageActivityAsync(new DelegatingTurnContext<IMessageActivity>(turnContext), cancellationToken).ConfigureAwait(false);
                break;
            ...
        }
    }

    protected virtual Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    ...
}
           

從上面sdk的源代碼就可以發現adapter調用了EchoBot的父類

ActivityHandler

OnTurnAsync()

方法,後者根據Activity的Type來調用到了

EchoBot

OnMessageActivityAsync

  1. 當我們在EchoBot裡調用

    SendActivityAsync()

    回複一條消息,會由Adapter來調用Azure Bot Service。

大家可以在 微軟botbuilder-dotnet repo 裡找到上面的源代碼。

繼續閱讀