EchoBot: как управление потоком из BotController в EchoBot - PullRequest
0 голосов
/ 04 июля 2019

Я смотрю на образец EchoBot и пытаюсь понять его. Я вижу, что BotController сопоставлен с api / messages и HttpPost, который, в свою очередь, вызывает Adapter.ProcessAsync. Но как это перевести в вызов EchoBot.OnMessageActivityAsync? Я попытался установить точку останова и посмотреть стек вызовов, но это не помогает (см. Прикрепленный скриншот).

enter image description here

Я понимаю, что BotFrameworkHttpAdapter вызывается через внедрение зависимостей. Но я не знаю, как мы в конечном итоге окажемся в EchoBot.

1 Ответ

1 голос
/ 04 июля 2019

Чтобы найти ответ на этот вопрос, вам действительно нужно погрузиться в исходный код, поэтому я надеюсь, что у вас есть снаряжение для подводного плавания, потому что мы углубляемся.

Шаг 1

Внутри BotController.cs файла следующий фрагмент кода называется:

await Adapter.ProcessAsync(Request, Response, Bot);

, который вызывает метод ProcessAsync на интерфейсе IBotFrameworkHttpAdapter.

Шаг 2

Внутри Startup.cs файла у нас есть следующая строка:

services.AddSingleton<IBotFrameworkHttpAdapter, BotFrameworkHttpAdapter>();

, в котором говорится, что каждый раз, когда мы запрашиваем IBotFrameworkHttpAdapter, предоставляем один и тот же экземпляр BotFrameworkHttpAdapter - по сути, статическую переменную, вы можете узнать больше о времени жизни службы внедрения зависимостей здесь .

Шаг 3

Внутри пакета Microsoft.Bot.Builder у нас есть реализация для метода ProcessAsync, которая для наших целей может быть сокращена до следующей строки:

var invokeResponse = await ProcessActivityAsync(authHeader, activity, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false);

, который вызывает ProcessActivityAsync, которая является другой функцией, которая живет в этой библиотеке - важная часть здесь - передаваемый параметр bot.OnTurnAsync.

Шаг 5

Также внутри пакета Microsoft.Bot.Builder находится реализация для ProcessActivityAsync:

return await ProcessActivityAsync(claimsIdentity, activity, callback, cancellationToken).ConfigureAwait(false);

, который вызывает перегрузку того же метода, но прежде чем мы перейдем отсюда, параметр callback - это параметр bot.OnTurnAsync, который был передан ранее.

Шаг 6

Перегрузка ProcessActivityAsync также реализована внутри пакета Microsoft.Bot.Builder и может быть упрощена до этой строки:

await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false);

, где 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);
    }
}

Однако на шаге 6 у нас также была эта строка:

using (var context = new TurnContext(this, activity))

, где создается контекст, а свойство действия - initialized . Этот же context передается на вызов RunPipelineAsync, что означает, что мы не провалимся на блок else ...

Но есть следующий комментарий к методу RunPipelineAsync:

/// <param name="callback">A callback method to run at the end of the pipeline.</param>

и внутри секции remarks:

...Once control reaches the end of the pipeline, the adapter calls
the <paramref name="callback"/> method...

Поэтому я уверен, что можно с уверенностью сказать, что наш метод 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>();

Реализация EchoBot наследуется от ActivityHandler класса:

public class EchoBot : ActivityHandler

Шаг 9

Класс ActivityHandler обеспечивает реализацию по умолчанию для метода OnTurnAsync, который я упрощу до:

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

который метод 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);
}

, когда вводимые пользователем данные возвращаются к ним, и, таким образом, наше путешествие заканчивается.


Что касается шага 7, команда Microsoft довольно активно работает с SO для вещей, помеченных botframework, поэтому может быть лучше получить @mdrichardson или @tdurnford, чтобы уточнить, что здесь происходит.


Помимо Visual Studio, вы можете отладить некоторый библиотечный код, включив следующую опцию:

  • Сервис -> Параметры -> Отладчик
  • Снимите флажок «Включить только мой код»

Также, если вы включите навигацию к декомпилированным источникам (вам нужно будет принять всплывающее уведомление), выполнив this :

  • Сервис -> Параметры -> Текстовый редактор -> C # -> Дополнительно
  • Установите флажок «Включить навигацию к декомпилированным источникам»

Вы сможете проверить исходный код внешних пакетов в самой Visual Studio.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...