Простой способ справиться с этим - просто перепроверить текст, который говорит пользователю нажать на кнопку, которая уже была отправлена. Вы можете сделать это с помощью свойства RetryPrompt
PromptOptions
. (Обратите внимание, что это не сработает, если бот отправит печатное действие.)
return await stepContext.BeginDialogAsync(
nameof(OAuthPrompt),
new PromptOptions
{
RetryPrompt = MessageFactory.Text("Please click the sign-in button.")
}, cancellationToken);
Если вы действительно хотите повторно выполнить повторную компоновку со всей картой, у вас есть два варианта, и оба они довольно сложны.
Вариант 1. Создайте карту самостоятельно
Фактическая карта, используемая в приглашении OAuth, создается в закрытом методе, поэтому вы не можете вызвать этот код. Вам нужно взглянуть на исходный код и скопировать его для собственного использования:
// Ensure prompt initialized
if (prompt == null)
{
prompt = Activity.CreateMessageActivity();
}
if (prompt.Attachments == null)
{
prompt.Attachments = new List<Attachment>();
}
// Append appropriate card if missing
if (!ChannelSupportsOAuthCard(turnContext.Activity.ChannelId))
{
if (!prompt.Attachments.Any(a => a.Content is SigninCard))
{
var link = await adapter.GetOauthSignInLinkAsync(turnContext, _settings.OAuthAppCredentials, _settings.ConnectionName, cancellationToken).ConfigureAwait(false);
prompt.Attachments.Add(new Attachment
{
ContentType = SigninCard.ContentType,
Content = new SigninCard
{
Text = _settings.Text,
Buttons = new[]
{
new CardAction
{
Title = _settings.Title,
Value = link,
Type = ActionTypes.Signin,
},
},
},
});
}
}
else if (!prompt.Attachments.Any(a => a.Content is OAuthCard))
{
var cardActionType = ActionTypes.Signin;
string signInLink = null;
if (turnContext.Activity.IsFromStreamingConnection())
{
signInLink = await adapter.GetOauthSignInLinkAsync(turnContext, _settings.OAuthAppCredentials, _settings.ConnectionName, cancellationToken).ConfigureAwait(false);
}
else if (turnContext.TurnState.Get<ClaimsIdentity>("BotIdentity") is ClaimsIdentity botIdentity && SkillValidation.IsSkillClaim(botIdentity.Claims))
{
// Force magic code for Skills (to be addressed in R8)
signInLink = await adapter.GetOauthSignInLinkAsync(turnContext, _settings.ConnectionName, cancellationToken).ConfigureAwait(false);
cardActionType = ActionTypes.OpenUrl;
}
prompt.Attachments.Add(new Attachment
{
ContentType = OAuthCard.ContentType,
Content = new OAuthCard
{
Text = _settings.Text,
ConnectionName = _settings.ConnectionName,
Buttons = new[]
{
new CardAction
{
Title = _settings.Title,
Text = _settings.Text,
Type = cardActionType,
Value = signInLink
}
}
}
});
}
Вы заметите, что этот код использует другой закрытый метод с именем ChannelSupportsOAuthCard
, и если канал не поддерживает карты OAuth, вместо этого он использует карту входа. Вы не упомянули, какой канал вы используете, поэтому я включил оба случая здесь, но если вы знаете, что все каналы, которые вы используете, поддерживают карты OAuth, то вы можете просто использовать код карты OAuth. В качестве альтернативы, если вы не хотите, чтобы какой-либо из ваших каналов использовал карты OAuth, вы можете просто использовать код карты входа. Создав действие с картой в нем, вы можете использовать его как для свойств Prompt
, так и RetryPrompt
параметров вашей подсказки:
return await stepContext.BeginDialogAsync(
nameof(OAuthPrompt),
new PromptOptions
{
Prompt = prompt,
RetryPrompt = prompt
}, cancellationToken);
Вариант 2. Перезапустите диалоговое окно
Если вы действительно не хотите беспокоиться о создании карты самостоятельно, единственный способ использовать встроенный код для этой цели - снова вызвать BeginDialogAsync
. Есть несколько способов подойти к этому, но я постараюсь go по простейшему маршруту.
Похоже, у вас уже есть некоторые функции "попробуйте еще раз" в LoginStepAsync
, где вы заканчиваете диалог, и я предположим, что любой код, который вы вызываете MainDialog
, автоматически начнет его снова при следующем повороте. Если вы не хотите ждать следующего хода, вы можете использовать небольшую хитрость, когда вы заменяете диалог на себя:
await stepContext.Context.SendActivityAsync(MessageFactory.Text("Login was not successful please try again."), cancellationToken);
return await stepContext.ReplaceDialogAsync(nameof(WaterfallDialog), cancellationToken: cancellationToken);
Конечно, чтобы перейти к шагу LoginStepAsync
, вы нужен способ завершить запрос OAuth, когда пользователь что-то печатает. Вы можете сделать это, вернув true
из валидатора приглашения:
AddDialog(new OAuthPrompt(
nameof(OAuthPrompt),
new OAuthPromptSettings
{
ConnectionName = configuration["ConnectionName"],
Text = "Please Sign In",
Title = "Sign In",
Timeout = 300000, // User has 5 minutes to login (1000 * 60 * 5)
}, (_, _) => Task.FromResult(true)));
В этом примере валидатор приглашения всегда будет возвращать true
и, таким образом, завершит запрос на следующем ходу, несмотря ни на что. Если вы хотите, вы можете поместить свой собственный лог c в валидатор, чтобы он проверял активность и результат распознавателя и принимал решение на основании этого. Но как только подсказка заканчивается, и водопад переходит к следующему шагу, LoginStepAsync
увидит нулевой ответ токена и узнает, что ему нужно перезапустить диалог.