我正在查看 EchoBot 示例并试图理解它。我看到 BotController 映射到 api/messages 和 HttpPost,后者又调用 Adapter.ProcessAsync。但这如何转化为 EchoBot.OnMessageActivityAsync 调用?我尝试设置断点并查看调用堆栈,但这无济于事(请参阅附加的屏幕截图)。
我知道 BotFrameworkHttpAdapter 是通过依赖注入调用的。但我不知道我们最终是如何进入 EchoBot 的。
要找到这个问题的答案,您确实必须深入研究源代码,所以我希望您已经准备好水肺潜水装备,因为我们正在深入研究。
第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)
哪里callback是bot.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我们传递的一个实例IBot的ProcessAsync方法,而在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 中,您可以通过启用以下选项来调试一些库代码:
此外,如果您启用导航到反编译源(你将不得不接受法律通知弹出)做这个:
您将能够在 Visual Studio 本身内检查外部包的源代码。
| 归档时间: |
|
| 查看次数: |
273 次 |
| 最近记录: |