EchoBot:如何控制从 BotController 到 EchoBot 的流

Pra*_*wat 1 botframework

我正在查看 EchoBot 示例并试图理解它。我看到 BotController 映射到 api/messages 和 HttpPost,后者又调用 Adapter.ProcessAsync。但这如何转化为 EchoBot.OnMessageActivityAsync 调用?我尝试设置断点并查看调用堆栈,但这无济于事(请参阅附加的屏幕截图)。

在此处输入图片说明

我知道 BotFrameworkHttpAdapter 是通过依赖注入调用的。但我不知道我们最终是如何进入 EchoBot 的。

Mat*_*ett 5

要找到这个问题的答案,您确实必须深入研究源代码,所以我希望您已经准备好水肺潜水装备,因为我们正在深入研究。

第1步

BotController.cs 文件内部,调用了以下代码:

await Adapter.ProcessAsync(Request, Response, Bot);
Run Code Online (Sandbox Code Playgroud)

它调用接口ProcessAsync上的方法IBotFrameworkHttpAdapter

第2步

Startup.cs 文件中,我们有以下行:

services.AddSingleton<IBotFrameworkHttpAdapter, BotFrameworkHttpAdapter>();
Run Code Online (Sandbox Code Playgroud)

这表示每次我们请求IBotFrameworkHttpAdapter, 提供相同的实例BotFrameworkHttpAdapter- 本质上是一个静态变量,您可以在此处阅读有关依赖注入服务生命周期的更多信息。

第 3 步

Microsoft.Bot.Builder包,我们有实现ProcessAsync方法,可以为我们的目的归纳为以下行:

var invokeResponse = await ProcessActivityAsync(authHeader, activity, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)

which 调用ProcessActivityAsyncwhich 是该库中的另一个函数——这里的重要部分是bot.OnTurnAsync传入的参数。

第 5 步

另外,里面Microsoft.Bot.Builder包的是实现ProcessActivityAsync

return await ProcessActivityAsync(claimsIdentity, activity, callback, cancellationToken).ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)

它调用了相同方法的重载,但在我们从这里继续之前,callback参数是bot.OnTurnAsync之前传递的参数。

第 6 步

的重载ProcessActivityAsync也在包内部实现Microsoft.Bot.Builder,可以简化为这一行:

await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false);
Run Code Online (Sandbox Code Playgroud)

哪里callbackbot.OnTurnAsync

第 7 步

更深的挖掘还是我们找到了实现的的RunPipelineAsync的的方法中Microsoft.Bot.Builder是人,事情开始变得有点模糊包......从理论上讲,我们希望通过掉在else哪里块callback(即bot.OnTurnAsync)被称为:

// Call any registered Middleware Components looking for ReceiveActivityAsync()
if (turnContext.Activity != null)
{
    // Other code  
}
else
{
    // call back to caller on proactive case
    if (callback != null)
    {
        await callback(turnContext, cancellationToken).ConfigureAwait(false);
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,回到第 6 步,我们也有这一行:

using (var context = new TurnContext(this, activity))
Run Code Online (Sandbox Code Playgroud)

创建上下文并初始化活动属性的位置。这同样context是传递到RunPipelineAsync调用,这意味着我们不会落入 else 块......

但是对RunPipelineAsync方法有以下评论:

/// <param name="callback">A callback method to run at the end of the pipeline.</param>
Run Code Online (Sandbox Code Playgroud)

并在该remarks部分内:

...Once control reaches the end of the pipeline, the adapter calls
the <paramref name="callback"/> method...
Run Code Online (Sandbox Code Playgroud)

所以我相信可以肯定地说我们的callback方法正在执行,这意味着我们继续通过冒泡返回链来解析callback映射到 ( bot.OnTurnAsync)的函数。

第 8 步

BotController我们传递的一个实例IBotProcessAsync方法,而在Startup我们连线了所有请求的IBot返回的实例EchoBot如下所示:

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

EchoBot 实现继承自ActivityHandler该类:

public class EchoBot : ActivityHandler
Run Code Online (Sandbox Code Playgroud)

步骤 9

ActivityHandler类提供了一个默认的实现OnTurnAsync,我将简化的方法:

switch (turnContext.Activity.Type)
{
   case ActivityTypes.Message:
       return OnMessageActivityAsync(new DelegatingTurnContext<IMessageActivity>(turnContext), cancellationToken);
   // Other cases
}
Run Code Online (Sandbox Code Playgroud)

OnMessageActivityAsync上有一个相同的类方法的实现,它返回一个完成的任务,即是一个空操作,但它是一个虚拟的方法-类继承它ActivityHandler可以提供自己的实现。

第 10 步

自定义实现OnMessageActivityAsync内部设置EchoBot类:

protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
    await turnContext.SendActivityAsync(MessageFactory.Text($"Echo: {turnContext.Activity.Text}"), cancellationToken);
}
Run Code Online (Sandbox Code Playgroud)

用户的输入被回显到他们那里,我们的旅程就这样结束了。


关于第 7 步,Microsoft 团队在 SO 上非常活跃,botframework因为它带有标记的东西,因此最好让 @mdrichardson 或 @tdurnford 澄清这里发生的事情。


在 Visual Studio 中,您可以通过启用以下选项来调试一些库代码:

  • 工具 --> 选项 --> 调试器
  • 取消选中“仅启用我的代码”

此外,如果您启用导航到反编译源(你将不得不接受法律通知弹出)做这个

  • 工具 --> 选项 --> 文本编辑器 --> C# --> 高级
  • 选中“启用导航到反编译源”

您将能够在 Visual Studio 本身内检查外部包的源代码。