В файле Startup.cs
Я начну с вашего файла Startup.cs
, поскольку именно там находится первая проблема, затем я предложу альтернативный дизайн.
То, что вы эффективно делаете со следующим блоком кода:
services.AddSingleton<GreetingDialog>();
services.AddTransient<IBot, AuthBot<GreetingDialog>>();
services.AddSingleton<GetPersonInfoDialog>();
services.AddTransient<IBot, AuthBot<GetPersonInfoDialog>>();
- Регистрация одного экземпляра
GreetingDialog
для вашего бота (по сути, статический). - Регистрация интерфейса
IBot
для возврата нового AuthBot
типа GreetingDialog
каждый раз, когда запрашивается IBot
. - Регистрация одного экземпляра
GetPersonInfoDialog
для вашего бота(по сути, статический). - Регистрация интерфейса
IBot
(снова) для возврата нового AuthBot
типа GetPersonInfoDialog
каждый раз, когда запрашивается IBot
(который перезапишет регистрацию на шаге 2).
Вы можете больше узнать о сроке службы здесь .
Итак, что вы на самом деле хотите, больше похоже на ниже:
public void ConfigureServices(IServiceCollection services)
{
// Other code
// Register dialogs
services.AddTransient<GreetingDialog>();
services.AddTransient<GetPersonInfoDialog>();
// Some more code
// Configure bot
services.AddTransient<IBot, DialogBot<GreetingDialog>>();
}
Сообщение об ошибке
DialogContext.BeginDialogAsync (): Aдиалог с идентификатором приветствия не найден.Диалог должен быть включен в текущий или родительский DialogSet.Например, при создании подкласса ComponentDialog вы можете вызвать AddDialog () в своем конструкторе.
Это сообщение об ошибке вызвано тем, что ваш GetPersonInfoDialog
не знает о вашем GreetingDialog
(и не должент).Я считаю, что это ошибка во время выполнения, потому что я помню, как столкнулся с подобной проблемой сам.Поскольку вы не предоставили полную реализацию для вашего GetPersonInfoDialog
класса, я должен предположить, что где-то там вы пытаетесь сделать что-то вроде следующего:
dialogContext.BeginDialogAsync("greeting");
or
dialogContext.BeginDialogAsync(nameof(GreetingDialog));
согласно документации первый параметр - это идентификатор диалога для запуска , этот идентификатор также используется для извлечения диалога из стека диалогов.Чтобы вызвать один диалог из другого, вам нужно добавить его в родительский диалог DialogSet
.Принятый способ сделать это - добавить вызов внутри конструктора для родительского диалога, например, так:
public ParentDialog(....)
: base(nameof(ParentDialog)
{
// Some code
// Important part
AddDialog(new ChildDialog(nameof(ChildDialog)));
}
При этом используется метод AddDialog , предоставленный Microsoft.Bot.Builder.Диалоги пакета NuGet и доступны через класс ComponentDialog
.
Затем, когда вы хотите отобразить ChildDialog
, вы бы позвонили:
dialogContext.BeginDialogAsync(nameof(ChildDialog));
В вашем случае вы можете заменить ParentDialog
с GetPersonInfoDialog
и ChildDialog
с GreetingDialog
.Поскольку ваш GreetingDialog
может быть использован только один раз (это не служебный диалог, который можно вызывать несколько раз, а с разными аргументами - в этом случае вы захотите указать конкретный идентификатор вместо использования nameof(GreetingDialog)
), этоМожно использовать строковое представление имени класса в качестве DialogId, вы можете использовать «приветствие» внутри вызова AddDialog
, но вам также придется обновить вызов BeginDialogAsync
, чтобы также использовать «приветствие».
Альтернативный дизайн
Поскольку я не верю, что вы хотите, чтобы GreetingDialog
или GetPersonInfoDialog
были вашими фактическими отправными точками, я бы предложил добавить еще один диалогназывается MainDialog
, который наследуется от класса RouterDialog
(пакет Microsoft.Bot.Builder.Solutions.Dialogs NuGet).Основываясь на архитектуре (Virtual Assistant Template) здесь , вы получите MainDialog
spawn от ваших GreetingDialog
и GetPersonInfoDialog
.
Предполагая, что ваш GreetingDialog
- это только один этап, когда он отправляет карту или какой-либо текст пользователю, чтобы приветствовать их, он может быть полностью заменен методом OnStartAsync
, который отправляет вашу карту / сообщение.Получение вашего пользователя к вашему GetPersonInfoDialog
будет затем обрабатываться с помощью RouteAsync
метода , например, здесь .
Изменения, которые вам нужно будет внести в существующий проект, чтобы подключить это,(при условии, что вы сохраняете GreetingDialog
):
- Добавить временные регистрации в
Startup.cs
для GreetingDialog
, GetPersonInfoDialog
и MainDialog
. - Добавить временную регистрациюдля отображения
IBot
в AuthBot<MainDialog>
- Добавить вызовы внутри конструктора
MainDialog
, чтобы добавить дочерние диалоги GreetingDialog
и GetPersonInfoDialog
. - В
OnBeginDialog
или OnStartAsync
из MainDialog
начать свой GreetingDialog
. - В
RouteAsync
из MainDialog
обрабатывайте любые условия вокруг отображения GetPersonInfoDialog
перед его отображением.
- Могут быть некоторые дополнительные шаги, которые я пропустил.
Полезные ссылки:
Редактировать
Чтобы достичь того, что вы хотите в OAuth-примере , вы можете сделать следующее:
В LogoutDialog.cs изменить:
private async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
до
protected virtual async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
В MainDialog.cs добавить:
protected override async Task<DialogTurnResult> InterruptAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
{
if (innerDc.Context.Activity.Type == ActivityTypes.Message)
{
var text = innerDc.Context.Activity.Text.ToLowerInvariant();
if (text == "check email")
{
//
return innerDc.BeginDialogAsync(/*TODO*/);
}
else if (text == "check calender")
{
//
return innerDc.BeginDialogAsync(/*TODO*/);
}
// etc
return await base.InterruptAsync(innerDc, cancellationToken);
}
return null;
}
вместе с регистрацией ваших диалогов календаря, электронной почты и т. Д. В конструкторе для MainDialog
с использованием метода AddDialog
.
Я бы посоветовал вам обратить внимание на использование шаблона Virtual Assistant . Поскольку он использует LUIS для определения намерений пользователя (проверьте электронную почту, проверьте календарь) и т.д.), затем направьте их соответствующим образом, соответствующий код находится в , этот метод . Преимущество использования LUIS для определения намерений заключается в возможности связать несколько способов запроса одного и того же намерения, поэтому вы не полагаетесь на то, что ваши пользователи явно набирают «проверить календарь», вы можете «показать мне мой календарь». "," какова моя готовность к следующему понедельнику "," свободен ли я сегодня днем "," проверьте, есть ли у меня какие-либо встречи завтра "и т. д. Фактически Microsoft уже создала Skills для электронной почты и календарь, который Для работы с шаблоном Virtual Assistant достаточно просто перенести код входа в систему для этого шаблона.