Beispiel #1
0
 protected override Task <DialogTurnResult> EndComponentAsync(DialogContext outerDc, object result, CancellationToken cancellationToken)
 {
     return(outerDc.EndDialogAsync());
 }
        public override async Task<DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (options is CancellationToken)
            {
                throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
            }

            var dcState = dc.GetState();

            if (this.Disabled != null && this.Disabled.GetValue(dcState))
            {
                return await dc.EndDialogAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
            }

            if (ItemsProperty == null)
            {
                throw new Exception($"EditArray: \"{ChangeType}\" operation couldn't be performed because the arrayProperty wasn't specified.");
            }

            var array = dcState.GetValue<JArray>(this.ItemsProperty.GetValue(dcState), () => new JArray());

            object item = null;
            object result = null;

            switch (ChangeType.GetValue(dcState))
            {
                case ArrayChangeType.Pop:
                    item = array[array.Count - 1];
                    array.RemoveAt(array.Count - 1);
                    result = item;
                    break;
                case ArrayChangeType.Push:
                    EnsureValue();
                    var (itemResult, error) = this.Value.TryGetValue(dcState);
                    if (error == null && itemResult != null)
                    {
                        array.Add(itemResult);
                    }

                    break;
                case ArrayChangeType.Take:
                    if (array.Count == 0)
                    {
                        break;
                    }

                    item = array[0];
                    array.RemoveAt(0);
                    result = item;
                    break;
                case ArrayChangeType.Remove:
                    EnsureValue();
                    (itemResult, error) = this.Value.TryGetValue(dcState);
                    if (error == null && itemResult != null)
                    {
                        result = false;
                        for (var i = 0; i < array.Count(); ++i)
                        {
                            if (array[i].ToString() == itemResult.ToString() || JToken.DeepEquals(array[i], JToken.FromObject(itemResult)))
                            {
                                result = true;
                                array.RemoveAt(i);
                                break;
                            }
                        }
                    }

                    break;
                case ArrayChangeType.Clear:
                    result = array.Count > 0;
                    array.Clear();
                    break;
            }

            dcState.SetValue(this.ItemsProperty.GetValue(dcState), array);

            if (ResultProperty != null)
            {
                dcState.SetValue(this.ResultProperty.GetValue(dcState), result);
            }

            return await dc.EndDialogAsync(result);
        }
Beispiel #3
0
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var activity = innerDc.Context.Activity;

            if (activity.IsStartActivity())
            {
                await OnStartAsync(innerDc);
            }

            switch (activity.Type)
            {
            case ActivityTypes.Message:
            {
                if (activity.Value != null)
                {
                    await OnEventAsync(innerDc);
                }
                else if (!string.IsNullOrEmpty(activity.Text))
                {
                    var result = await innerDc.ContinueDialogAsync();

                    switch (result.Status)
                    {
                    case DialogTurnStatus.Empty:
                    {
                        await RouteAsync(innerDc);

                        // Waterfalls with no turns should Complete.
                        if (innerDc.Stack.Count == 0)
                        {
                            await CompleteAsync(innerDc);
                        }
                        break;
                    }

                    case DialogTurnStatus.Complete:
                    {
                        await CompleteAsync(innerDc);

                        // End active dialog
                        await innerDc.EndDialogAsync();

                        break;
                    }

                    default:
                    {
                        break;
                    }
                    }
                }

                break;
            }

            case ActivityTypes.Event:
            {
                await OnEventAsync(innerDc);

                break;
            }

            default:
            {
                await OnSystemMessageAsync(innerDc);

                break;
            }
            }

            return(EndOfTurn);
        }
        // Runs on every turn of the conversation to check if the conversation should be interrupted.
        protected async Task <DialogTurnResult> InterruptDialogAsync(DialogContext innerDc, CancellationToken cancellationToken)
        {
            DialogTurnResult interrupted = null;
            var activity = innerDc.Context.Activity;

            if (activity.Type == ActivityTypes.Message && !string.IsNullOrEmpty(activity.Text))
            {
                // Get connected LUIS result from turn state.
                var generalResult = innerDc.Context.TurnState.Get <GeneralLuis>(StateProperties.GeneralLuisResultKey);
                (var generalIntent, var generalScore) = generalResult.TopIntent();

                if (generalScore > 0.5)
                {
                    switch (generalIntent)
                    {
                    case GeneralLuis.Intent.Cancel:
                    {
                        await innerDc.Context.SendActivityAsync(_templateManager.GenerateActivity(MainResponses.CancelMessage), cancellationToken);

                        await innerDc.CancelAllDialogsAsync(cancellationToken);

                        if (innerDc.Context.IsSkill())
                        {
                            interrupted = await innerDc.EndDialogAsync(cancellationToken : cancellationToken);
                        }
                        else
                        {
                            interrupted = await innerDc.BeginDialogAsync(InitialDialogId, cancellationToken : cancellationToken);
                        }

                        break;
                    }

                    case GeneralLuis.Intent.Help:
                    {
                        await innerDc.Context.SendActivityAsync(_templateManager.GenerateActivity(MainResponses.HelpMessage), cancellationToken);

                        await innerDc.RepromptDialogAsync(cancellationToken);

                        interrupted = EndOfTurn;
                        break;
                    }

                    case GeneralLuis.Intent.Logout:
                    {
                        await OnLogoutAsync(innerDc, cancellationToken);

                        await innerDc.Context.SendActivityAsync(_templateManager.GenerateActivity(MainResponses.LogOut), cancellationToken);

                        await innerDc.CancelAllDialogsAsync(cancellationToken);

                        if (innerDc.Context.IsSkill())
                        {
                            interrupted = await innerDc.EndDialogAsync(cancellationToken : cancellationToken);
                        }
                        else
                        {
                            interrupted = await innerDc.BeginDialogAsync(InitialDialogId, cancellationToken : cancellationToken);
                        }

                        break;
                    }
                    }
                }
            }

            return(interrupted);
        }
        /// <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(CancellationToken))
        {
            if (dc == null)
            {
                throw new ArgumentNullException(nameof(dc));
            }

            var dcState     = dc.GetState();
            var interrupted = dcState.GetValue <bool>(TurnPath.INTERRUPTED, () => false);
            var turnCount   = dcState.GetValue <int>(TURN_COUNT_PROPERTY, () => 0);

            // Recognize token
            var recognized = await RecognizeTokenAsync(dc, cancellationToken).ConfigureAwait(false);

            // Check for timeout
            var state       = dc.ActiveDialog.State;
            var expires     = (DateTime)state[PersistedExpires];
            var isMessage   = dc.Context.Activity.Type == ActivityTypes.Message;
            var hasTimedOut = isMessage && (DateTime.Compare(DateTime.Now, expires) > 0);

            if (hasTimedOut)
            {
                if (this.Property != null)
                {
                    dcState.SetValue(this.Property.GetValue(dcState), null);
                }

                // if the token fetch request times out, complete the prompt with no result.
                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }
            else
            {
                var promptState   = (IDictionary <string, object>)state[PersistedState];
                var promptOptions = (PromptOptions)state[PersistedOptions];

                // Increment attempt count
                // Convert.ToInt32 For issue https://github.com/Microsoft/botbuilder-dotnet/issues/1859
                promptState[AttemptCountKey] = Convert.ToInt32(promptState[AttemptCountKey]) + 1;

                // Validate the return value
                var inputState = InputState.Invalid;
                if (recognized.Succeeded)
                {
                    inputState = InputState.Valid;
                }

                // Return recognized value or re-prompt
                if (inputState == InputState.Valid)
                {
                    if (this.Property != null)
                    {
                        dcState.SetValue(this.Property.GetValue(dcState), recognized.Value);
                    }

                    return(await dc.EndDialogAsync(recognized.Value, cancellationToken).ConfigureAwait(false));
                }
                else if (this.MaxTurnCount == null || turnCount < this.MaxTurnCount.GetValue(dcState))
                {
                    // increase the turnCount as last step
                    dcState.SetValue(TURN_COUNT_PROPERTY, turnCount + 1);
                    var prompt = await this.OnRenderPrompt(dc, inputState).ConfigureAwait(false);

                    await dc.Context.SendActivityAsync(prompt).ConfigureAwait(false);
                    await SendOAuthCardAsync(dc, promptOptions?.Prompt, cancellationToken).ConfigureAwait(false);

                    return(Dialog.EndOfTurn);
                }
                else
                {
                    if (this.DefaultValue != null)
                    {
                        var(value, _) = this.DefaultValue.TryGetValue(dcState);
                        if (this.DefaultValueResponse != null)
                        {
                            var response = await this.DefaultValueResponse.BindToData(dc.Context, dcState).ConfigureAwait(false);

                            await dc.Context.SendActivityAsync(response).ConfigureAwait(false);
                        }

                        // set output property
                        dcState.SetValue(this.Property.GetValue(dcState), value);
                        return(await dc.EndDialogAsync(value).ConfigureAwait(false));
                    }
                }

                return(await dc.EndDialogAsync().ConfigureAwait(false));
            }
        }
Beispiel #6
0
 protected override async Task <DialogTurnResult> OnBreakLoopAsync(DialogContext dc, ActionScopeResult actionScopeResult, CancellationToken cancellationToken = default)
 {
     return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
 }
Beispiel #7
0
            public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dialogContext, object options = null, CancellationToken cancellationToken = default)
            {
                var lg = dialogContext.Services.Get <LanguageGenerator>();

                // en-us locale
                dialogContext.Context.Activity.Locale = "en-us";
                Assert.IsNotNull(lg, "ILanguageGenerator should not be null");
                Assert.IsNotNull(dialogContext.Services.Get <ResourceExplorer>(), "ResourceExplorer should not be null");

                var result = await lg.GenerateAsync(dialogContext, "${templatea()}", null);

                Assert.AreEqual("from a.en-us.lg", result);

                // import b.en-us.lg
                result = await lg.GenerateAsync(dialogContext, "${templateb()}", null);

                Assert.AreEqual("from b.en-us.lg", result);

                // fallback to c.en.lg
                result = await lg.GenerateAsync(dialogContext, "${templatec()}", null);

                Assert.AreEqual("from c.en.lg", result);

                // there is no 'greeting' template in b.en-us.lg, fallback to a.lg to find it.
                result = await lg.GenerateAsync(dialogContext, "${greeting()}", null);

                Assert.AreEqual("hi", result);

                //en locale
                dialogContext.Context.Activity.Locale = "en";
                Assert.IsNotNull(lg, "ILanguageGenerator should not be null");
                Assert.IsNotNull(dialogContext.Services.Get <ResourceExplorer>(), "ResourceExplorer should not be null");

                result = await lg.GenerateAsync(dialogContext, "${templatea()}", null);

                Assert.AreEqual("from a.lg", result);

                // import b.en-us.lg
                result = await lg.GenerateAsync(dialogContext, "${templateb()}", null);

                Assert.AreEqual("from b.lg", result);

                // c.en.lg is ignore in b.lg
                result = await lg.GenerateAsync(dialogContext, "${templatec()}", null);

                Assert.AreEqual("from c.lg", result);

                // there is no 'greeting' template in b.en-us.lg, fallback to a.lg to find it.
                result = await lg.GenerateAsync(dialogContext, "${greeting()}", null);

                Assert.AreEqual("hi", result);

                // empty locale
                dialogContext.Context.Activity.Locale = string.Empty;
                result = await lg.GenerateAsync(dialogContext, "${templatea()}", null);

                Assert.AreEqual("from a.lg", result);

                result = await lg.GenerateAsync(dialogContext, "${templateb()}", null);

                Assert.AreEqual("from b.lg", result);

                // ignore the "en" in c.en.lg, just load c.lg
                result = await lg.GenerateAsync(dialogContext, "${templatec()}", null);

                Assert.AreEqual("from c.lg", result);

                result = await lg.GenerateAsync(dialogContext, "${greeting()}", null);

                Assert.AreEqual("hi", result);

                return(await dialogContext.EndDialogAsync());
            }
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options, CancellationToken cancellationToken = default(CancellationToken))
        {
            await dc.Context.SendActivityAsync($"{dc.Context.Activity.Text} is wrong commond.Please input 'order' to reorder");

            return(await dc.EndDialogAsync());
        }
Beispiel #9
0
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (options is CancellationToken)
            {
                throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
            }

            if (this.Disabled != null && this.Disabled.GetValue(dc.State) == true)
            {
                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }

            lock (this.Condition)
            {
                if (this.caseExpressions == null)
                {
                    this.caseExpressions = new Dictionary <string, Expression>();

                    foreach (var @case in this.Cases)
                    {
                        if (long.TryParse(@case.Value, out long intVal))
                        {
                            // you don't have to put quotes around numbers, "23" => 23 OR "23"
                            this.caseExpressions[@case.Value] = Expression.OrExpression(
                                Expression.EqualsExpression(this.Condition, Expression.ConstantExpression(intVal)),
                                Expression.EqualsExpression(this.Condition, Expression.ConstantExpression(@case.Value)));
                        }
                        else if (float.TryParse(@case.Value, out float floatVal))
                        {
                            // you don't have to put quotes around numbers, "23" => 23 OR "23"
                            this.caseExpressions[@case.Value] = Expression.OrExpression(
                                Expression.EqualsExpression(this.Condition, Expression.ConstantExpression(floatVal)),
                                Expression.EqualsExpression(this.Condition, Expression.ConstantExpression(@case.Value)));
                        }
                        else if (bool.TryParse(@case.Value, out bool boolVal))
                        {
                            // you don't have to put quotes around bools, "true" => true OR "true"
                            this.caseExpressions[@case.Value] = Expression.OrExpression(
                                Expression.EqualsExpression(this.Condition, Expression.ConstantExpression(boolVal)),
                                Expression.EqualsExpression(this.Condition, Expression.ConstantExpression(@case.Value)));
                        }
                        else
                        {
                            // if someone does "=23" that will be numeric comparison or "='23'" that will be string comparison, or it can be a
                            // real expression bound to memory.
                            var(value, _) = new ValueExpression(@case.Value).TryGetValue(dc.State);
                            this.caseExpressions[@case.Value] = Expression.EqualsExpression(this.Condition, Expression.ConstantExpression(value));
                        }
                    }
                }
            }

            ActionScope actionScope = this.DefaultScope;

            foreach (var caseScope in this.Cases)
            {
                var(value, error) = this.caseExpressions[caseScope.Value].TryEvaluate(dc.State);

                // Compare both expression results. The current switch case triggers if the comparison is true.
                if (value != null && ((bool)value) == true)
                {
                    actionScope = caseScope;
                    break;
                }
            }

            return(await dc.ReplaceDialogAsync(actionScope.Id, null, cancellationToken : cancellationToken).ConfigureAwait(false));
        }
Beispiel #10
0
        private async Task <DialogTurnResult> ForwardToSkill(DialogContext dc, Activity activity)
        {
            try
            {
                if (!_skillInitialized)
                {
                    await InitializeSkill(dc);
                }

                _inProcAdapter.ProcessActivity(activity, async(skillContext, ct) =>
                {
                    await _activatedSkill.OnTurnAsync(skillContext);
                }).Wait();

                var queue             = new List <Activity>();
                var endOfConversation = false;
                var skillResponse     = _inProcAdapter.GetNextReply();

                while (skillResponse != null)
                {
                    if (skillResponse.Type == ActivityTypes.EndOfConversation)
                    {
                        endOfConversation = true;
                    }
                    else if (skillResponse?.Name == Events.TokenRequestEventName)
                    {
                        // Send trace to emulator
                        await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"<--Received a Token Request from a skill"));

                        if (!_useCachedTokens)
                        {
                            var adapter = dc.Context.Adapter as BotFrameworkAdapter;
                            var tokens  = await adapter.GetTokenStatusAsync(dc.Context, dc.Context.Activity.From.Id);

                            foreach (var token in tokens)
                            {
                                await adapter.SignOutUserAsync(dc.Context, token.ConnectionName, dc.Context.Activity.From.Id, default(CancellationToken));
                            }
                        }

                        var innerDc = await _dialogs.CreateContextAsync(dc.Context);

                        var authResult = await innerDc.BeginDialogAsync(nameof(MultiProviderAuthDialog));

                        if (authResult.Result?.GetType() == typeof(ProviderTokenResponse))
                        {
                            var tokenEvent = skillResponse.CreateReply();
                            tokenEvent.Type  = ActivityTypes.Event;
                            tokenEvent.Name  = Events.TokenResponseEventName;
                            tokenEvent.Value = authResult.Result as ProviderTokenResponse;

                            return(await ForwardToSkill(dc, tokenEvent));
                        }
                        else
                        {
                            return(authResult);
                        }
                    }
                    else
                    {
                        if (skillResponse.Type == ActivityTypes.Trace)
                        {
                            // Write out any trace messages from the skill to the emulator
                            await dc.Context.SendActivityAsync(skillResponse);
                        }
                        else
                        {
                            queue.Add(skillResponse);
                        }
                    }

                    skillResponse = _inProcAdapter.GetNextReply();
                }

                // send skill queue to User
                if (queue.Count > 0)
                {
                    var firstActivity = queue[0];
                    if (firstActivity.Conversation.Id == dc.Context.Activity.Conversation.Id)
                    {
                        // if the conversation id from the activity is the same as the context activity, it's reactive message
                        await dc.Context.SendActivitiesAsync(queue.ToArray());
                    }
                    else
                    {
                        // if the conversation id from the activity is differnt from the context activity, it's proactive message
                        await dc.Context.Adapter.ContinueConversationAsync(_endpointService.AppId, firstActivity.GetConversationReference(), CreateCallback(queue.ToArray()), default(CancellationToken));
                    }
                }

                // handle ending the skill conversation
                if (endOfConversation)
                {
                    await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"<--Ending the skill conversation"));

                    return(await dc.EndDialogAsync());
                }
                else
                {
                    return(EndOfTurn);
                }
            }
            catch
            {
                // something went wrong forwarding to the skill, so end dialog cleanly and throw so the error is logged.
                // NOTE: errors within the skill itself are handled by the OnTurnError handler on the adapter.
                await dc.EndDialogAsync();

                throw;
            }
        }
Beispiel #11
0
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var activity = innerDc.Context.Activity;

            switch (activity.Type)
            {
            case ActivityTypes.Message:
            {
                var result = await innerDc.ContinueDialogAsync();

                switch (result.Status)
                {
                case DialogTurnStatus.Empty:
                {
                    await RouteAsync(innerDc);

                    break;
                }

                case DialogTurnStatus.Complete:
                {
                    await CompleteAsync(innerDc);

                    // End active dialog.
                    await innerDc.EndDialogAsync();

                    break;
                }

                default:
                {
                    break;
                }
                }

                break;
            }

            case ActivityTypes.Event:
            {
                await OnEventAsync(innerDc);

                break;
            }

            case ActivityTypes.ConversationUpdate:
            {
                await OnStartAsync(innerDc);

                break;
            }

            default:
            {
                await OnSystemMessageAsync(innerDc);

                break;
            }
            }

            return(EndOfTurn);
        }
Beispiel #12
0
        private async Task InitializeSkill(DialogContext dc)
        {
            try
            {
                var skillDefinition    = dc.ActiveDialog.State[ActiveSkillStateKey] as SkillDefinition;
                var skillConfiguration = _skills[skillDefinition.Id];

                IStorage storage;

                if (skillConfiguration.CosmosDbOptions != null)
                {
                    var cosmosDbOptions = skillConfiguration.CosmosDbOptions;
                    cosmosDbOptions.CollectionId = skillDefinition.Name;
                    storage = new CosmosDbStorage(cosmosDbOptions);
                }
                else
                {
                    storage = new MemoryStorage();
                }

                // Initialize skill state
                var userState         = new UserState(storage);
                var conversationState = new ConversationState(storage);

                // Create skill instance
                try
                {
                    var skillType = Type.GetType(skillDefinition.Assembly);
                    _activatedSkill = (IBot)Activator.CreateInstance(skillType, skillConfiguration, conversationState, userState, null, true);
                }
                catch (Exception e)
                {
                    var message = $"Skill ({skillDefinition.Name}) could not be created.";
                    throw new InvalidOperationException(message, e);
                }

                _inProcAdapter = new InProcAdapter
                {
                    // set up skill turn error handling
                    OnTurnError = async(context, exception) =>
                    {
                        await context.SendActivityAsync(context.Activity.CreateReply($"Sorry, something went wrong trying to communicate with the skill. Please try again."));

                        // Send error trace to emulator
                        await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"Skill Error: {exception.Message} | {exception.StackTrace}"));

                        // Log exception in AppInsights
                        skillConfiguration.TelemetryClient.TrackException(exception);
                    },
                };

                _inProcAdapter.Use(new EventDebuggerMiddleware());
                _inProcAdapter.Use(new SetLocaleMiddleware(dc.Context.Activity.Locale ?? "zh-cn"));
                _inProcAdapter.Use(new AutoSaveStateMiddleware(userState, conversationState));
                _skillInitialized = true;
            }
            catch
            {
                // something went wrong initializing the skill, so end dialog cleanly and throw so the error is logged
                _skillInitialized = false;
                await dc.EndDialogAsync();

                throw;
            }
        }
Beispiel #13
0
 public override Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default)
 {
     return(dc.EndDialogAsync());
 }
        /// <inheritdoc/>
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (options is CancellationToken)
            {
                throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
            }

            if (Disabled != null && Disabled.GetValue(dc.State))
            {
                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }

            if (dc.Context.Activity.ChannelId != Channels.Msteams)
            {
                throw new InvalidOperationException($"{Kind} works only on the Teams channel.");
            }

            IActivity activity = null;

            if (Activity != null)
            {
                activity = await Activity.BindAsync(dc, dc.State).ConfigureAwait(false);
            }

            string teamsChannelId = TeamsChannelId.GetValueOrNull(dc.State);

            if (string.IsNullOrEmpty(teamsChannelId))
            {
                teamsChannelId = dc.Context.Activity.TeamsGetChannelId();
            }

            if (!(dc.Context.Adapter is BotFrameworkAdapter))
            {
                throw new InvalidOperationException($"{Kind} is not supported by the current adapter.");
            }

            // TODO: this will NOT work with certificate app credentials

            // TeamsInfo.SendMessageToTeamsChannelAsync requires AppCredentials
            var credentials = dc.Context.TurnState.Get <IConnectorClient>()?.Credentials as MicrosoftAppCredentials;

            if (credentials == null)
            {
                throw new InvalidOperationException($"Missing credentials as {nameof(MicrosoftAppCredentials)} in {nameof(IConnectorClient)} from TurnState");
            }

            // The result comes back as a tuple, which is used to set the two properties (if present).
            var result = await TeamsInfo.SendMessageToTeamsChannelAsync(dc.Context, activity, teamsChannelId, credentials, cancellationToken : cancellationToken).ConfigureAwait(false);

            if (ConversationReferenceProperty != null)
            {
                dc.State.SetValue(ConversationReferenceProperty.GetValue(dc.State), result.Item1);
            }

            if (ActivityIdProperty != null)
            {
                dc.State.SetValue(ActivityIdProperty.GetValue(dc.State), result.Item2);
            }

            return(await dc.EndDialogAsync(result, cancellationToken : cancellationToken).ConfigureAwait(false));
        }
Beispiel #15
0
 private static async Task <DialogTurnResult> ResetLanguage(DialogContext dc, System.Object options)
 {
     dc.State.SetValue("conversation.currLanguage", "English");
     return(await dc.EndDialogAsync());
 }
Beispiel #16
0
 /// <summary>
 /// Called when the inner dialog stack is complete.
 /// </summary>
 /// <param name="innerDc">The dialog context for the component.</param>
 /// <param name="result">The dialog result when inner dialog completed.</param>
 /// <param name="cancellationToken">The cancellation token.</param>
 /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
 protected virtual Task CompleteAsync(DialogContext innerDc, DialogTurnResult result = null, CancellationToken cancellationToken = default(CancellationToken))
 {
     innerDc.EndDialogAsync(result).Wait(cancellationToken);
     return(Task.CompletedTask);
 }
Beispiel #17
0
            public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default)
            {
                await dc.Context.SendActivityAsync("simple", cancellationToken : cancellationToken);

                return(await dc.EndDialogAsync(cancellationToken : cancellationToken));
            }
Beispiel #18
0
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var status = await OnInterruptDialogAsync(innerDc, cancellationToken).ConfigureAwait(false);

            if (status == InterruptionAction.MessageSentToUser)
            {
                // Resume the waiting dialog after interruption
                await innerDc.RepromptDialogAsync().ConfigureAwait(false);

                return(EndOfTurn);
            }
            else if (status == InterruptionAction.StartedDialog)
            {
                // Stack is already waiting for a response, shelve inner stack
                return(EndOfTurn);
            }
            else
            {
                var activity = innerDc.Context.Activity;

                if (activity.IsStartActivity())
                {
                    await OnStartAsync(innerDc).ConfigureAwait(false);
                }

                switch (activity.Type)
                {
                case ActivityTypes.Message:
                {
                    // Note: This check is a workaround for adaptive card buttons that should map to an event (i.e. startOnboarding button in intro card)
                    if (activity.Value != null)
                    {
                        await OnEventAsync(innerDc).ConfigureAwait(false);
                    }
                    else if (!string.IsNullOrEmpty(activity.Text))
                    {
                        var result = await innerDc.ContinueDialogAsync().ConfigureAwait(false);

                        switch (result.Status)
                        {
                        case DialogTurnStatus.Empty:
                        {
                            await RouteAsync(innerDc).ConfigureAwait(false);

                            break;
                        }

                        case DialogTurnStatus.Complete:
                        {
                            await CompleteAsync(innerDc).ConfigureAwait(false);

                            // End active dialog
                            await innerDc.EndDialogAsync().ConfigureAwait(false);

                            break;
                        }

                        default:
                        {
                            break;
                        }
                        }
                    }

                    break;
                }

                case ActivityTypes.Event:
                {
                    await OnEventAsync(innerDc).ConfigureAwait(false);

                    break;
                }

                case ActivityTypes.Invoke:
                {
                    // Used by Teams for Authentication scenarios.
                    await innerDc.ContinueDialogAsync().ConfigureAwait(false);

                    break;
                }

                default:
                {
                    await OnSystemMessageAsync(innerDc).ConfigureAwait(false);

                    break;
                }
                }

                return(EndOfTurn);
            }
        }
        /// <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(CancellationToken))
        {
            if (dc == null)
            {
                throw new ArgumentNullException(nameof(dc));
            }

            var interrupted = dc.State.GetValue <bool>(TurnPath.Interrupted, () => false);
            var turnCount   = dc.State.GetValue <int>(TURN_COUNT_PROPERTY, () => 0);

            // Recognize token
            var recognized = await RecognizeTokenAsync(dc, cancellationToken).ConfigureAwait(false);

            // Check for timeout
            var state                 = dc.ActiveDialog.State;
            var expires               = (DateTime)state[PersistedExpires];
            var isMessage             = dc.Context.Activity.Type == ActivityTypes.Message;
            var isTimeoutActivityType = isMessage ||
                                        IsTokenResponseEvent(dc.Context) ||
                                        IsTeamsVerificationInvoke(dc.Context) ||
                                        IsTokenExchangeRequestInvoke(dc.Context);
            var hasTimedOut = isTimeoutActivityType && (DateTime.Compare(DateTime.UtcNow, expires) > 0);

            if (hasTimedOut)
            {
                if (this.Property != null)
                {
                    dc.State.SetValue(this.Property.GetValue(dc.State), null);
                }

                // if the token fetch request times out, complete the prompt with no result.
                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }
            else
            {
                var promptState   = (IDictionary <string, object>)state[PersistedState];
                var promptOptions = (PromptOptions)state[PersistedOptions];

                // Increment attempt count
                // Convert.ToInt32 For issue https://github.com/Microsoft/botbuilder-dotnet/issues/1859
                promptState[AttemptCountKey] = Convert.ToInt32(promptState[AttemptCountKey], CultureInfo.InvariantCulture) + 1;

                // Validate the return value
                var inputState = InputState.Invalid;
                if (recognized.Succeeded)
                {
                    inputState = InputState.Valid;
                }

                // Return recognized value or re-prompt
                if (inputState == InputState.Valid)
                {
                    if (this.Property != null)
                    {
                        dc.State.SetValue(this.Property.GetValue(dc.State), recognized.Value);
                    }

                    return(await dc.EndDialogAsync(recognized.Value, cancellationToken).ConfigureAwait(false));
                }
                else if (this.MaxTurnCount == null || turnCount < this.MaxTurnCount.GetValue(dc.State))
                {
                    if (!interrupted)
                    {
                        // increase the turnCount as last step
                        dc.State.SetValue(TURN_COUNT_PROPERTY, turnCount + 1);

                        if (isMessage)
                        {
                            var prompt = await this.OnRenderPromptAsync(dc, inputState, cancellationToken).ConfigureAwait(false);

                            await dc.Context.SendActivityAsync(prompt, cancellationToken).ConfigureAwait(false);
                        }
                    }

                    // Only send the card in response to a message.
                    if (isMessage)
                    {
                        await SendOAuthCardAsync(dc, promptOptions?.Prompt, cancellationToken).ConfigureAwait(false);
                    }

                    return(Dialog.EndOfTurn);
                }
                else
                {
                    if (this.DefaultValue != null)
                    {
                        var(value, _) = this.DefaultValue.TryGetValue(dc.State);
                        if (this.DefaultValueResponse != null)
                        {
                            var response = await this.DefaultValueResponse.BindAsync(dc, cancellationToken : cancellationToken).ConfigureAwait(false);

                            var properties = new Dictionary <string, string>()
                            {
                                { "template", JsonConvert.SerializeObject(this.DefaultValueResponse) },
                                { "result", response == null ? string.Empty : JsonConvert.SerializeObject(response, new JsonSerializerSettings()
                                    {
                                        NullValueHandling = NullValueHandling.Ignore
                                    }) },
                                { "context", TelemetryLoggerConstants.OAuthInputResultEvent }
                            };
                            TelemetryClient.TrackEvent(TelemetryLoggerConstants.GeneratorResultEvent, properties);
                            await dc.Context.SendActivityAsync(response, cancellationToken).ConfigureAwait(false);
                        }

                        // set output property
                        dc.State.SetValue(this.Property.GetValue(dc.State), value);
                        return(await dc.EndDialogAsync(value, cancellationToken).ConfigureAwait(false));
                    }
                }

                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }
        }
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (options is CancellationToken)
            {
                throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
            }

            var client = new HttpClient();

            // Single command running with a copy of the original data
            client.DefaultRequestHeaders.Clear();

            JToken instanceBody = null;

            if (this.Body != null)
            {
                instanceBody = (JToken)this.Body.DeepClone();
            }

            var instanceHeaders = Headers == null ? null : new Dictionary <string, string>(Headers);
            var instanceUrl     = this.Url;

            instanceUrl = await new TextTemplate(this.Url).BindToData(dc.Context, dc.GetState()).ConfigureAwait(false);

            // Bind each string token to the data in state
            if (instanceBody != null)
            {
                await ReplaceJTokenRecursively(dc, instanceBody);
            }

            // Set headers
            if (instanceHeaders != null)
            {
                foreach (var unit in instanceHeaders)
                {
                    client.DefaultRequestHeaders.Add(
                        await new TextTemplate(unit.Key).BindToData(dc.Context, dc.GetState()),
                        await new TextTemplate(unit.Value).BindToData(dc.Context, dc.GetState()));
                }
            }

            dynamic traceInfo = new JObject();

            traceInfo.request        = new JObject();
            traceInfo.request.method = this.Method.ToString();
            traceInfo.request.url    = instanceUrl;

            HttpResponseMessage response = null;

            switch (this.Method)
            {
            case HttpMethod.POST:
                if (instanceBody == null)
                {
                    response = await client.PostAsync(instanceUrl, null);
                }
                else
                {
                    var postContent = new StringContent(instanceBody.ToString(), Encoding.UTF8, "application/json");
                    traceInfo.request.content = instanceBody.ToString();
                    traceInfo.request.headers = JObject.FromObject(postContent?.Headers.ToDictionary(t => t.Key, t => (object)t.Value?.FirstOrDefault()));
                    response = await client.PostAsync(instanceUrl, postContent);
                }

                break;

            case HttpMethod.PATCH:
                if (instanceBody == null)
                {
                    var request = new HttpRequestMessage(new System.Net.Http.HttpMethod("PATCH"), instanceUrl);
                    response = await client.SendAsync(request);
                }
                else
                {
                    var request = new HttpRequestMessage(new System.Net.Http.HttpMethod("PATCH"), instanceUrl);
                    request.Content           = new StringContent(instanceBody.ToString(), Encoding.UTF8, "application/json");
                    traceInfo.request.content = instanceBody.ToString();
                    traceInfo.request.headers = JObject.FromObject(request.Content.Headers.ToDictionary(t => t.Key, t => (object)t.Value?.FirstOrDefault()));
                    response = await client.SendAsync(request);
                }

                break;

            case HttpMethod.PUT:
                if (instanceBody == null)
                {
                    response = await client.PutAsync(instanceUrl, null);
                }
                else
                {
                    var putContent = new StringContent(instanceBody.ToString(), Encoding.UTF8, "application/json");
                    traceInfo.request.content = instanceBody.ToString();
                    traceInfo.request.headers = JObject.FromObject(putContent.Headers.ToDictionary(t => t.Key, t => (object)t.Value?.FirstOrDefault()));
                    response = await client.PutAsync(instanceUrl, putContent);
                }

                break;

            case HttpMethod.DELETE:
                response = await client.DeleteAsync(instanceUrl);

                break;

            case HttpMethod.GET:
                response = await client.GetAsync(instanceUrl);

                break;
            }

            Result requestResult = new Result(response.Headers)
            {
                StatusCode   = (int)response.StatusCode,
                ReasonPhrase = response.ReasonPhrase,
            };

            object content = (object)await response.Content.ReadAsStringAsync();

            switch (this.ResponseType)
            {
            case ResponseTypes.Activity:
                var activity = JsonConvert.DeserializeObject <Activity>((string)content);
                requestResult.Content = JObject.FromObject(activity);
                await dc.Context.SendActivityAsync(activity, cancellationToken : cancellationToken).ConfigureAwait(false);

                break;

            case ResponseTypes.Activities:
                var activities = JsonConvert.DeserializeObject <Activity[]>((string)content);
                requestResult.Content = JObject.FromObject(activities);
                await dc.Context.SendActivitiesAsync(activities, cancellationToken : cancellationToken).ConfigureAwait(false);

                break;

            case ResponseTypes.Json:
                // Try set with JOjbect for further retreiving
                try
                {
                    content = JToken.Parse((string)content);
                }
                catch
                {
                    content = content.ToString();
                }

                requestResult.Content = content;
                break;

            case ResponseTypes.None:
            default:
                break;
            }

            traceInfo.response = JObject.FromObject(requestResult);

            // Write Trace Activity for the http request and response values
            await dc.Context.TraceActivityAsync("HttpRequest", (object)traceInfo, valueType : "Microsoft.HttpRequest", label : this.Id).ConfigureAwait(false);

            if (this.ResultProperty != null)
            {
                dc.GetState().SetValue(this.ResultProperty, requestResult);
            }

            // return the actionResult as the result of this operation
            return(await dc.EndDialogAsync(result : requestResult, cancellationToken : cancellationToken));
        }
Beispiel #21
0
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (options is CancellationToken)
            {
                throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
            }

            if (this.Disabled != null && this.Disabled.GetValue(dc.State) == true)
            {
                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }

            lock (this.Condition)
            {
                if (this.caseExpressions == null)
                {
                    this.caseExpressions = new Dictionary <string, Expression>();

                    foreach (var cse in this.Cases)
                    {
                        Expression caseExpression = null;

                        // Values for cases are always coerced to constant
                        if (long.TryParse(cse.Value, out long i))
                        {
                            caseExpression = Expression.ConstantExpression(i);
                        }
                        else if (float.TryParse(cse.Value, out float f))
                        {
                            caseExpression = Expression.ConstantExpression(f);
                        }
                        else if (bool.TryParse(cse.Value, out bool b))
                        {
                            caseExpression = Expression.ConstantExpression(b);
                        }
                        else
                        {
                            caseExpression = Expression.ConstantExpression(cse.Value);
                        }

                        var caseCondition = Expression.EqualsExpression(this.Condition, caseExpression);

                        // Map of expression to actions
                        this.caseExpressions[cse.Value] = caseCondition;
                    }
                }
            }

            ActionScope actionScope = this.DefaultScope;

            foreach (var caseScope in this.Cases)
            {
                var(value, error) = this.caseExpressions[caseScope.Value].TryEvaluate(dc.State);

                if (error != null)
                {
                    throw new Exception($"Expression evaluation resulted in an error. Expression: {caseExpressions[caseScope.Value].ToString()}. Error: {error}");
                }

                // Compare both expression results. The current switch case triggers if the comparison is true.
                if (((bool)value) == true)
                {
                    actionScope = caseScope;
                    break;
                }
            }

            return(await dc.ReplaceDialogAsync(actionScope.Id, null, cancellationToken : cancellationToken).ConfigureAwait(false));
        }
Beispiel #22
0
            public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dialogContext, object options = null, CancellationToken cancellationToken = default)
            {
                var lg = dialogContext.Services.Get <LanguageGenerator>();

                // en-us locale
                dialogContext.State.SetValue("turn.locale", "en-us");
                Assert.NotNull(lg);
                Assert.NotNull(dialogContext.Services.Get <ResourceExplorer>());

                var result = await lg.GenerateAsync(dialogContext, "${templatea()}", null);

                Assert.Equal("from a.en-us.lg", result);

                // import b.en-us.lg
                result = await lg.GenerateAsync(dialogContext, "${templateb()}", null);

                Assert.Equal("from b.en-us.lg", result);

                // fallback to c.en.lg
                result = await lg.GenerateAsync(dialogContext, "${templatec()}", null);

                Assert.Equal("from c.en.lg", result);

                // there is no 'greeting' template in b.en-us.lg, fallback to a.lg to find it.
                result = await lg.GenerateAsync(dialogContext, "${greeting()}", null);

                Assert.Equal("hi", result);

                //en locale
                dialogContext.State.SetValue("turn.locale", "en");
                Assert.NotNull(lg);
                Assert.NotNull(dialogContext.Services.Get <ResourceExplorer>());

                result = await lg.GenerateAsync(dialogContext, "${templatea()}", null);

                Assert.Equal("from a.lg", result);

                // import b.en-us.lg
                result = await lg.GenerateAsync(dialogContext, "${templateb()}", null);

                Assert.Equal("from b.lg", result);

                // c.en.lg is ignore in b.lg
                result = await lg.GenerateAsync(dialogContext, "${templatec()}", null);

                Assert.Equal("from c.lg", result);

                // there is no 'greeting' template in b.en-us.lg, fallback to a.lg to find it.
                result = await lg.GenerateAsync(dialogContext, "${greeting()}", null);

                Assert.Equal("hi", result);

                // empty locale
                dialogContext.State.SetValue("turn.locale", string.Empty);
                Thread.CurrentThread.CurrentCulture   = new CultureInfo("fr-fr");
                dialogContext.Context.Activity.Locale = "fr-fr";
                result = await lg.GenerateAsync(dialogContext, "${templatea()}", null);

                Assert.Equal("from a.lg", result);

                result = await lg.GenerateAsync(dialogContext, "${templateb()}", null);

                Assert.Equal("from b.lg", result);

                // ignore the "en" in c.en.lg, just load c.lg
                result = await lg.GenerateAsync(dialogContext, "${templatec()}", null);

                Assert.Equal("from c.lg", result);

                result = await lg.GenerateAsync(dialogContext, "${greeting()}", null);

                Assert.Equal("hi", result);

                return(await dialogContext.EndDialogAsync());
            }
Beispiel #23
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="innerDc">The inner <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.
        ///
        /// By default, this calls <see cref="InterruptableDialog.OnInterruptDialogAsync(DialogContext, CancellationToken)"/>
        /// then routes the activity to the waiting active dialog, or to a handling method based on its activity type.
        /// </remarks>
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
        {
            // Check for any interruptions.
            var status = await OnInterruptDialogAsync(innerDc, cancellationToken).ConfigureAwait(false);

            if (status == InterruptionAction.Resume)
            {
                // Interruption message was sent, and the waiting dialog should resume/reprompt.
                await innerDc.RepromptDialogAsync().ConfigureAwait(false);
            }
            else if (status == InterruptionAction.Waiting)
            {
                // Interruption intercepted conversation and is waiting for user to respond.
                return(EndOfTurn);
            }
            else if (status == InterruptionAction.End)
            {
                // Interruption ended conversation, and current dialog should end.
                return(await innerDc.EndDialogAsync().ConfigureAwait(false));
            }
            else if (status == InterruptionAction.NoAction)
            {
                // No interruption was detected. Process activity normally.
                var activity = innerDc.Context.Activity;

                switch (activity.Type)
                {
                case ActivityTypes.Message:
                {
                    // Pass message to waiting child dialog.
                    var result = await innerDc.ContinueDialogAsync().ConfigureAwait(false);

                    if (result.Status == DialogTurnStatus.Empty)
                    {
                        // There was no waiting dialog on the stack, process message normally.
                        await OnMessageActivityAsync(innerDc).ConfigureAwait(false);
                    }

                    break;
                }

                case ActivityTypes.Event:
                {
                    await OnEventActivityAsync(innerDc).ConfigureAwait(false);

                    break;
                }

                case ActivityTypes.Invoke:
                {
                    // Used by Teams for Authentication scenarios.
                    await innerDc.ContinueDialogAsync().ConfigureAwait(false);

                    break;
                }

                case ActivityTypes.ConversationUpdate:
                {
                    await OnMembersAddedAsync(innerDc).ConfigureAwait(false);

                    break;
                }

                default:
                {
                    // All other activity types will be routed here. Custom handling should be added in implementation.
                    await OnUnhandledActivityTypeAsync(innerDc).ConfigureAwait(false);

                    break;
                }
                }
            }

            if (innerDc.ActiveDialog == null)
            {
                // If the inner dialog stack completed during this turn, this component should be ended.
                return(await innerDc.EndDialogAsync().ConfigureAwait(false));
            }

            return(EndOfTurn);
        }
Beispiel #24
0
        protected override async Task RouteAsync(DialogContext dc,
                                                 CancellationToken cancellationToken = default(CancellationToken))
        {
            // Check dispatch result
            var dispatchResult =
                await _services.DispatchRecognizer.RecognizeAsync <Dispatch>(dc, CancellationToken.None);

            var intent = dispatchResult.TopIntent().intent;

            if (intent == Dispatch.Intent.l_general)
            {
                // If dispatch result is general luis model
                _services.LuisServices.TryGetValue("general", out var luisService);

                if (luisService == null)
                {
                    throw new Exception(
                              "The specified LUIS Model could not be found in your Bot Services configuration.");
                }
                else
                {
                    var result = await luisService.RecognizeAsync <General>(dc, CancellationToken.None);

                    var generalIntent = result?.TopIntent().intent;

                    // switch on general intents
                    switch (generalIntent)
                    {
                    case General.Intent.Cancel:
                    {
                        // send cancelled response
                        await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Cancelled);


                        // Cancel any active dialogs on the stack
                        await dc.EndDialogAsync();

                        await dc.CancelAllDialogsAsync();

                        break;
                    }

                    case General.Intent.Escalate:
                    {
                        // start escalate dialog
                        await dc.BeginDialogAsync(nameof(EscalateDialog));

                        break;
                    }

                    case General.Intent.Help:
                    {
                        // send help response
                        await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Help);

                        break;
                    }

                    case General.Intent.Tar:
                    {
                        // start escalate dialog
                        await dc.BeginDialogAsync(nameof(TarDialog));

                        break;
                    }

                    case General.Intent.Benefits:
                    {
                        // send help response
                        await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Help);

                        break;
                    }

                    case General.Intent.Immigration:
                    {
                        // start escalate dialog
                        await dc.BeginDialogAsync(nameof(ImmigrationDialog));

                        break;
                    }

                    case General.Intent.None:
                    default:
                    {
                        // No intent was identified, send confused message
                        await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Confused);

                        break;
                    }
                    }
                }
            }
            else if (intent == Dispatch.Intent.q_faq)
            {
                _services.QnAServices.TryGetValue("faq", out var qnaService);

                if (qnaService == null)
                {
                    throw new Exception(
                              "The specified QnA Maker Service could not be found in your Bot Services configuration.");
                }
                else
                {
                    var answers = await qnaService.GetAnswersAsync(dc.Context);

                    if (answers != null && answers.Count() > 0)
                    {
                        await dc.Context.SendActivityAsync(answers[0].Answer);
                    }
                }
            }
            else if (intent == Dispatch.Intent.q_chitchat)
            {
                _services.QnAServices.TryGetValue("chitchat", out var qnaService);

                if (qnaService == null)
                {
                    throw new Exception(
                              "The specified QnA Maker Service could not be found in your Bot Services configuration.");
                }
                else
                {
                    var answers = await qnaService.GetAnswersAsync(dc.Context);

                    if (answers != null && answers.Count() > 0)
                    {
                        await dc.Context.SendActivityAsync(answers[0].Answer);
                    }
                }
            }
            else
            {
                // If dispatch intent does not map to configured models, send "confused" response.
                await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Confused);
            }
        }
        /// <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(CancellationToken))
        {
            if (dc == null)
            {
                throw new ArgumentNullException(nameof(dc));
            }

            if (options is CancellationToken)
            {
                throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
            }

            var dcState = dc.GetState();

            if (this.Disabled != null && this.Disabled.GetValue(dcState))
            {
                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }

            PromptOptions opt = null;

            if (options != null)
            {
                if (options is PromptOptions)
                {
                    // Ensure prompts have input hint set
                    opt = options as PromptOptions;
                    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;
                    }
                }
            }

            var op = OnInitializeOptions(dc, options);

            dcState.SetValue(ThisPath.OPTIONS, op);
            dcState.SetValue(TURN_COUNT_PROPERTY, 0);

            // If AlwaysPrompt is set to true, then clear Property value for turn 0.
            var(alwaysPrompt, _) = this.AlwaysPrompt.TryGetValue(dcState);

            if (this.Property != null && alwaysPrompt)
            {
                dcState.SetValue(this.Property.GetValue(dcState), null);
            }

            // Initialize state
            var state = dc.ActiveDialog.State;

            state[PersistedOptions] = opt;
            state[PersistedState]   = new Dictionary <string, object>
            {
                { AttemptCountKey, 0 },
            };

            state[PersistedExpires] = DateTime.Now.AddMilliseconds(Timeout.GetValue(dcState));

            // Attempt to get the users token
            if (!(dc.Context.Adapter is IUserTokenProvider adapter))
            {
                throw new InvalidOperationException("OAuthPrompt.Recognize(): not supported by the current adapter");
            }

            var output = await adapter.GetUserTokenAsync(dc.Context, ConnectionName.GetValue(dcState), null, cancellationToken).ConfigureAwait(false);

            if (output != null)
            {
                if (this.Property != null)
                {
                    dcState.SetValue(this.Property.GetValue(dcState), output);
                }

                // Return token
                return(await dc.EndDialogAsync(output, cancellationToken).ConfigureAwait(false));
            }
            else
            {
                dcState.SetValue(TURN_COUNT_PROPERTY, 1);

                // Prompt user to login
                await SendOAuthCardAsync(dc, opt?.Prompt, cancellationToken).ConfigureAwait(false);

                return(Dialog.EndOfTurn);
            }
        }
        // Runs on every turn of the conversation to check if the conversation should be interrupted.
        protected async Task <DialogTurnResult> InterruptDialogAsync(DialogContext innerDc, CancellationToken cancellationToken)
        {
            DialogTurnResult interrupted = null;
            var activity = innerDc.Context.Activity;

            if (activity.Type == ActivityTypes.Message && !string.IsNullOrEmpty(activity.Text))
            {
                // Get connected LUIS result from turn state.
                var generalResult = innerDc.Context.TurnState.Get <General>(StateProperties.GeneralLuisResultKey);
                (var generalIntent, var generalScore) = generalResult.TopIntent();

                if (generalScore > 0.5)
                {
                    switch (generalIntent)
                    {
                    case General.Intent.Cancel:
                    {
                        await innerDc.Context.SendActivityAsync(_templateManager.GenerateActivity(POISharedResponses.CancellingMessage), cancellationToken);

                        await innerDc.CancelAllDialogsAsync(cancellationToken);

                        if (innerDc.Context.IsSkill())
                        {
                            var state = await _stateAccessor.GetAsync(innerDc.Context, () => new PointOfInterestSkillState(), cancellationToken);

                            interrupted = await innerDc.EndDialogAsync(state.IsAction?new SingleDestinationResponse { ActionSuccess = false } : null, cancellationToken : cancellationToken);
                        }
                        else
                        {
                            interrupted = await innerDc.BeginDialogAsync(InitialDialogId, cancellationToken : cancellationToken);
                        }

                        break;
                    }

                    case General.Intent.Help:
                    {
                        await innerDc.Context.SendActivityAsync(_templateManager.GenerateActivity(POIMainResponses.HelpMessage), cancellationToken);

                        await innerDc.RepromptDialogAsync(cancellationToken);

                        interrupted = EndOfTurn;
                        break;
                    }

                    case General.Intent.Logout:
                    {
                        // Log user out of all accounts.
                        await LogUserOutAsync(innerDc, cancellationToken);

                        await innerDc.Context.SendActivityAsync(_templateManager.GenerateActivity(POIMainResponses.LogOut), cancellationToken);

                        await innerDc.CancelAllDialogsAsync(cancellationToken);

                        if (innerDc.Context.IsSkill())
                        {
                            var state = await _stateAccessor.GetAsync(innerDc.Context, () => new PointOfInterestSkillState(), cancellationToken);

                            interrupted = await innerDc.EndDialogAsync(state.IsAction?new SingleDestinationResponse { ActionSuccess = false } : null, cancellationToken : cancellationToken);
                        }
                        else
                        {
                            interrupted = await innerDc.BeginDialogAsync(InitialDialogId, cancellationToken : cancellationToken);
                        }

                        break;
                    }
                    }
                }
            }

            return(interrupted);
        }
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (options is CancellationToken)
            {
                throw new ArgumentException($"{nameof(options)} cannot be a cancellation token");
            }

            if (this.Disabled != null && this.Disabled.GetValue(dc.State) == true)
            {
                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }

#pragma warning disable CA2000 // Dispose objects before losing scope (excluding for now, to fix this we would need to understand better how HttpClient gets into turn state and determine if we should dispose it or not, this should also be analyzed once we start using HttpClientFactory).
            var client = dc.Context.TurnState.Get <HttpClient>() ?? new HttpClient();
#pragma warning restore CA2000 // Dispose objects before losing scope

            // Single command running with a copy of the original data
            client.DefaultRequestHeaders.Clear();

            JToken instanceBody = null;
            if (this.Body != null)
            {
                var(body, err) = this.Body.TryGetValue(dc.State);
                if (err != null)
                {
                    throw new ArgumentException(err);
                }

                instanceBody = (JToken)JToken.FromObject(body).DeepClone();
            }

            var instanceHeaders = Headers == null ? null : Headers.ToDictionary(kv => kv.Key, kv => kv.Value.GetValue(dc.State));

            var(instanceUrl, instanceUrlError) = this.Url.TryGetValue(dc.State);
            if (instanceUrlError != null)
            {
                throw new ArgumentException(instanceUrlError);
            }

            // Bind each string token to the data in state
            instanceBody = instanceBody?.ReplaceJTokenRecursively(dc.State);

            // Set headers
            if (instanceHeaders != null)
            {
                foreach (var unit in instanceHeaders)
                {
                    client.DefaultRequestHeaders.TryAddWithoutValidation(unit.Key, unit.Value);
                }
            }

            dynamic traceInfo = new JObject();

            traceInfo.request        = new JObject();
            traceInfo.request.method = this.Method.ToString();
            traceInfo.request.url    = instanceUrl;

            HttpResponseMessage response = null;
            string contentType           = ContentType?.GetValue(dc.State) ?? "application/json";

            switch (this.Method)
            {
            case HttpMethod.POST:
                if (instanceBody == null)
                {
                    response = await client.PostAsync(instanceUrl, content : null, cancellationToken : cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    using (var postContent = new StringContent(instanceBody.ToString(), Encoding.UTF8, contentType))
                    {
                        traceInfo.request.content = instanceBody.ToString();
                        traceInfo.request.headers = JObject.FromObject(postContent?.Headers.ToDictionary(t => t.Key, t => (object)t.Value?.FirstOrDefault()));
                        response = await client.PostAsync(instanceUrl, postContent, cancellationToken).ConfigureAwait(false);
                    }
                }

                break;

            case HttpMethod.PATCH:
                if (instanceBody == null)
                {
                    using (var request = new HttpRequestMessage(new System.Net.Http.HttpMethod("PATCH"), instanceUrl))
                    {
                        response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
                    }
                }
                else
                {
                    using (var request = new HttpRequestMessage(new System.Net.Http.HttpMethod("PATCH"), instanceUrl))
                    {
                        request.Content           = new StringContent(instanceBody.ToString(), Encoding.UTF8, contentType);
                        traceInfo.request.content = instanceBody.ToString();
                        traceInfo.request.headers = JObject.FromObject(request.Content.Headers.ToDictionary(t => t.Key, t => (object)t.Value?.FirstOrDefault()));
                        response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false);
                    }
                }

                break;

            case HttpMethod.PUT:
                if (instanceBody == null)
                {
                    response = await client.PutAsync(instanceUrl, content : null, cancellationToken : cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    using (var putContent = new StringContent(instanceBody.ToString(), Encoding.UTF8, contentType))
                    {
                        traceInfo.request.content = instanceBody.ToString();
                        traceInfo.request.headers = JObject.FromObject(putContent.Headers.ToDictionary(t => t.Key, t => (object)t.Value?.FirstOrDefault()));
                        response = await client.PutAsync(instanceUrl, putContent, cancellationToken).ConfigureAwait(false);
                    }
                }

                break;

            case HttpMethod.DELETE:
                response = await client.DeleteAsync(instanceUrl, cancellationToken).ConfigureAwait(false);

                break;

            case HttpMethod.GET:
                response = await client.GetAsync(instanceUrl, cancellationToken).ConfigureAwait(false);

                break;
            }

            var requestResult = new Result(response.Headers)
            {
                StatusCode   = (int)response.StatusCode,
                ReasonPhrase = response.ReasonPhrase,
            };

            object content = (object)await response.Content.ReadAsStringAsync().ConfigureAwait(false);

            switch (this.ResponseType.GetValue(dc.State))
            {
            case ResponseTypes.Activity:
                var activity = JsonConvert.DeserializeObject <Activity>((string)content);
                requestResult.Content = JObject.FromObject(activity);
                await dc.Context.SendActivityAsync(activity, cancellationToken : cancellationToken).ConfigureAwait(false);

                break;

            case ResponseTypes.Activities:
                var activities = JsonConvert.DeserializeObject <Activity[]>((string)content);
                requestResult.Content = JArray.FromObject(activities);
                await dc.Context.SendActivitiesAsync(activities, cancellationToken : cancellationToken).ConfigureAwait(false);

                break;

            case ResponseTypes.Json:
                // Try set with JOjbect for further retrieving
                try
                {
                    content = JToken.Parse((string)content);
                }
#pragma warning disable CA1031 // Do not catch general exception types (just stringify the content if we can't parse the content).
                catch
#pragma warning restore CA1031 // Do not catch general exception types
                {
                    content = content.ToString();
                }

                requestResult.Content = content;
                break;

            case ResponseTypes.Binary:
                // Try to resolve binary data
                var bytes = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false);

                requestResult.Content = bytes;
                break;

            case ResponseTypes.None:
            default:
                break;
            }

            traceInfo.response = JObject.FromObject(requestResult);

            // Write Trace Activity for the http request and response values
            await dc.Context.TraceActivityAsync("HttpRequest", (object)traceInfo, valueType : "Microsoft.HttpRequest", label : this.Id).ConfigureAwait(false);

            if (this.ResultProperty != null)
            {
                dc.State.SetValue(this.ResultProperty.GetValue(dc.State), requestResult);
            }

            // return the actionResult as the result of this operation
            return(await dc.EndDialogAsync(result : requestResult, cancellationToken : cancellationToken).ConfigureAwait(false));
        }
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext dc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            await dc.Context.SendActivityAsync(dc.State.GetValue <string>(dc.Context.Activity.Text));

            return(await dc.EndDialogAsync());
        }
 protected virtual async Task <DialogTurnResult> OnBreakLoopAsync(DialogContext dc, ActionScopeResult actionScopeResult, CancellationToken cancellationToken = default)
 {
     // default is to simply end the dialog and propagate to parent to handle
     return(await dc.EndDialogAsync(actionScopeResult, 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(CancellationToken))
        {
            if (dc == null)
            {
                throw new ArgumentNullException(nameof(dc));
            }

            // Recognize token
            var recognized = await RecognizeTokenAsync(dc.Context, cancellationToken).ConfigureAwait(false);

            // Check for timeout
            var state       = dc.ActiveDialog.State;
            var expires     = (DateTime)state[PersistedExpires];
            var isMessage   = dc.Context.Activity.Type == ActivityTypes.Message;
            var hasTimedOut = isMessage && (DateTime.Compare(DateTime.Now, expires) > 0);

            if (hasTimedOut)
            {
                if (this.TokenProperty != null)
                {
                    dc.State.SetValue(this.TokenProperty, null);
                }

                // if the token fetch request times out, complete the prompt with no result.
                return(await dc.EndDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false));
            }
            else
            {
                var promptState   = (IDictionary <string, object>)state[PersistedState];
                var promptOptions = (PromptOptions)state[PersistedOptions];

                // Increment attempt count
                // Convert.ToInt32 For issue https://github.com/Microsoft/botbuilder-dotnet/issues/1859
                promptState[AttemptCountKey] = Convert.ToInt32(promptState[AttemptCountKey]) + 1;

                // Validate the return value
                var isValid = false;
                if (recognized.Succeeded)
                {
                    isValid = true;
                }

                // Return recognized value or re-prompt
                if (isValid)
                {
                    if (this.TokenProperty != null)
                    {
                        dc.State.SetValue(this.TokenProperty, recognized.Value);
                    }

                    return(await dc.EndDialogAsync(recognized.Value, cancellationToken).ConfigureAwait(false));
                }
                else
                {
                    if (!dc.Context.Responded && isMessage && promptOptions != null && promptOptions.RetryPrompt != null)
                    {
                        await dc.Context.SendActivityAsync(promptOptions.RetryPrompt, cancellationToken).ConfigureAwait(false);
                    }

                    return(Dialog.EndOfTurn);
                }
            }
        }