예제 #1
0
 /// <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));
 }
예제 #2
0
 /// <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));
 }
예제 #3
0
        /// <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);
        }
예제 #4
0
 /// <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));
 }
예제 #5
0
        /// <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);
        }
예제 #6
0
 public static void Done(this DialogContext dc, object result)
 {
     dc.EndDialogAsync(result).Wait();
 }