/// <summary> /// Called when the dialog is _continued_, where it is the active dialog and the /// user replies with a new activity. /// </summary> /// <param name="dc">The <see cref="DialogContext"/> for the current turn of conversation.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <remarks>If the task is successful, the result indicates whether the dialog is still /// active after the turn has been processed by the dialog. The result may also contain a /// return value. /// /// If this method is *not* overridden, the dialog automatically ends when the user replies. /// </remarks> /// <seealso cref="DialogContext.ContinueDialogAsync(CancellationToken)"/> public virtual async Task <DialogTurnResult> ContinueDialogAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken)) { // By default just end the current dialog. return(await dc.EndDialogAsync(null, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Ends the component dialog in its parent's context. /// </summary> /// <param name="outerDc">The parent <see cref="DialogContext"/> for the current turn of conversation.</param> /// <param name="result">Optional, value to return from the dialog component to the parent context.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A task that represents the work queued to execute.</returns> /// <remarks>If the task is successful, the result indicates that the dialog ended after the /// turn was processed by the dialog. /// /// In general, the parent context is the dialog or bot turn handler that started the dialog. /// If the parent is a dialog, the stack calls the parent's /// <see cref="Dialog.ResumeDialogAsync(DialogContext, DialogReason, object, CancellationToken)"/> /// method to return a result to the parent dialog. If the parent dialog does not implement /// `ResumeDialogAsync`, then the parent will end, too, and the result is passed to the next /// parent context, if one exists. /// /// The returned <see cref="DialogTurnResult"/> contains the return value in its /// <see cref="DialogTurnResult.Result"/> property.</remarks> /// <seealso cref="BeginDialogAsync(DialogContext, object, CancellationToken)"/> /// <seealso cref="ContinueDialogAsync(DialogContext, CancellationToken)"/> protected virtual Task <DialogTurnResult> EndComponentAsync(DialogContext outerDc, object result, CancellationToken cancellationToken) { return(outerDc.EndDialogAsync(result, cancellationToken)); }
/// <summary> /// Called when a prompt dialog is pushed onto the dialog stack and is being activated. /// </summary> /// <param name="dc">The dialog context for the current turn of the conversation.</param> /// <param name="options">Optional, additional information to pass to the prompt being started.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <remarks>If the task is successful, the result indicates whether the prompt is still /// active after the turn has been processed by the prompt.</remarks> public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default) { if (dc == null) { throw new ArgumentNullException(nameof(dc)); } if (options is CancellationToken) { throw new ArgumentException($"{nameof(options)} cannot be a cancellation token", nameof(options)); } if (options != null && !(options is PromptOptions)) { throw new ArgumentException($"Parameter {nameof(options)} should be an instance of to {nameof(PromptOptions)} if provided", nameof(options)); } var opt = (PromptOptions)options; if (opt != null) { // Ensure prompts have input hint set if (opt.Prompt != null && string.IsNullOrEmpty(opt.Prompt.InputHint)) { opt.Prompt.InputHint = InputHints.AcceptingInput; } if (opt.RetryPrompt != null && string.IsNullOrEmpty(opt.RetryPrompt.InputHint)) { opt.RetryPrompt.InputHint = InputHints.AcceptingInput; } } // Initialize state var timeout = _settings.Timeout ?? (int)TurnStateConstants.OAuthLoginTimeoutValue.TotalMilliseconds; var state = dc.ActiveDialog.State; state[PersistedOptions] = opt; state[PersistedState] = new Dictionary <string, object> { { Prompt <int> .AttemptCountKey, 0 }, }; state[PersistedExpires] = DateTime.Now.AddMilliseconds(timeout); state[PersistedCaller] = CreateCallerInfo(dc.Context); // Attempt to get the users token if (!(dc.Context.Adapter is IExtendedUserTokenProvider adapter)) { throw new InvalidOperationException("OAuthPrompt.Recognize(): not supported by the current adapter"); } var output = await adapter.GetUserTokenAsync(dc.Context, _settings.OAuthAppCredentials, _settings.ConnectionName, null, cancellationToken).ConfigureAwait(false); if (output != null) { // Return token return(await dc.EndDialogAsync(output, cancellationToken).ConfigureAwait(false)); } // Prompt user to login await SendOAuthCardAsync(dc.Context, opt?.Prompt, cancellationToken).ConfigureAwait(false); return(EndOfTurn); }
/// <summary> /// Method called when an instance of the dialog is being returned to from another /// dialog that was started by the current instance using `DialogSet.begin()`. /// If this method is NOT implemented then the dialog will be automatically ended with a call /// to `DialogSet.endDialogWithResult()`. Any result passed from the called dialog will be passed /// to the current dialogs parent. /// </summary> /// <param name="dc">The dialog context for the current turn of conversation.</param> /// <param name="reason">Reason why the dialog resumed.</param> /// <param name="result">(Optional) value returned from the dialog that was called. The type of the value returned is dependant on the dialog that was called.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public virtual async Task <DialogTurnResult> ResumeDialogAsync(DialogContext dc, DialogReason reason, object result = null, CancellationToken cancellationToken = default(CancellationToken)) { // By default just end the current dialog and return result to parent. return(await dc.EndDialogAsync(result, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Called when a prompt dialog is the active dialog and the user replied with a new activity. /// </summary> /// <param name="dc">The dialog context for the current turn of conversation.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> /// <remarks>If the task is successful, the result indicates whether the dialog is still /// active after the turn has been processed by the dialog. /// <para>The prompt generally continues to receive the user's replies until it accepts the /// user's reply as valid input for the prompt.</para></remarks> public override async Task <DialogTurnResult> ContinueDialogAsync(DialogContext dc, CancellationToken cancellationToken = default) { if (dc == null) { throw new ArgumentNullException(nameof(dc)); } // Check for timeout var state = dc.ActiveDialog.State; var expires = (DateTime)state[PersistedExpires]; var isMessage = dc.Context.Activity.Type == ActivityTypes.Message; // If the incoming Activity is a message, or an Activity Type normally handled by OAuthPrompt, // check to see if this OAuthPrompt Expiration has elapsed, and end the dialog if so. var isTimeoutActivityType = isMessage || IsTokenResponseEvent(dc.Context) || IsTeamsVerificationInvoke(dc.Context) || IsTokenExchangeRequestInvoke(dc.Context); var hasTimedOut = isTimeoutActivityType && DateTime.Compare(DateTime.UtcNow, expires) > 0; if (hasTimedOut) { // if the token fetch request times out, complete the prompt with no result. return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false)); } // Recognize token var recognized = await RecognizeTokenAsync(dc, cancellationToken).ConfigureAwait(false); var promptState = state[PersistedState].CastTo <IDictionary <string, object> >(); var promptOptions = state[PersistedOptions].CastTo <PromptOptions>(); // Increment attempt count // Convert.ToInt32 For issue https://github.com/Microsoft/botbuilder-dotnet/issues/1859 promptState[Prompt <int> .AttemptCountKey] = Convert.ToInt32(promptState[Prompt <int> .AttemptCountKey], CultureInfo.InvariantCulture) + 1; // Validate the return value var isValid = false; if (_validator != null) { var promptContext = new PromptValidatorContext <TokenResponse>(dc.Context, recognized, promptState, promptOptions); isValid = await _validator(promptContext, cancellationToken).ConfigureAwait(false); } else if (recognized.Succeeded) { isValid = true; } // Return recognized value or re-prompt if (isValid) { return(await dc.EndDialogAsync(recognized.Value, cancellationToken).ConfigureAwait(false)); } else if (isMessage && _settings.EndOnInvalidMessage) { // If EndOnInvalidMessage is set, complete the prompt with no result. return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false)); } if (!dc.Context.Responded && isMessage && promptOptions?.RetryPrompt != null) { await dc.Context.SendActivityAsync(promptOptions.RetryPrompt, cancellationToken).ConfigureAwait(false); } return(EndOfTurn); }
public static void Done(this DialogContext dc, object result) { dc.EndDialogAsync(result).Wait(); }