Esempio n. 1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DialogContext"/> class.
        /// </summary>
        /// <param name="dialogs">Parent dialog set.</param>
        /// <param name="turnContext">Context for the current turn of conversation with the user.</param>
        /// <param name="state">Current dialog state.</param>
        public DialogContext(DialogSet dialogs, ITurnContext turnContext, DialogState state)
        {
            Dialogs = dialogs ?? throw new ArgumentNullException(nameof(dialogs));
            Context = turnContext ?? throw new ArgumentNullException(nameof(turnContext));

            Stack = state.DialogStack;
        }
        public override async Task <DialogTurnResult> DialogBeginAsync(DialogContext dc, DialogOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (dc == null)
            {
                throw new ArgumentNullException(nameof(dc));
            }

            // Start the inner dialog.
            var dialogState = new DialogState();

            dc.ActiveDialog.State[PersistedDialogState] = dialogState;
            var cdc        = new DialogContext(_dialogs, dc.Context, dialogState);
            var turnResult = await OnDialogBeginAsync(cdc, options, cancellationToken).ConfigureAwait(false);

            // Check for end of inner dialog
            if (turnResult.HasResult)
            {
                // Return result to calling dialog
                return(await dc.EndAsync(turnResult.Result, cancellationToken).ConfigureAwait(false));
            }
            else
            {
                // Just signal end of turn
                return(Dialog.EndOfTurn);
            }
        }
Esempio n. 3
0
        public override async Task <DialogTurnResult> BeginDialogAsync(DialogContext outerDc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (outerDc == null)
            {
                throw new ArgumentNullException(nameof(outerDc));
            }

            // Start the inner dialog.
            var dialogState = new DialogState();

            outerDc.ActiveDialog.State[PersistedDialogState] = dialogState;
            var innerDc    = new DialogContext(_dialogs, outerDc.Context, dialogState);
            var turnResult = await OnBeginDialogAsync(innerDc, options, cancellationToken).ConfigureAwait(false);

            // Check for end of inner dialog
            if (turnResult.Status != DialogTurnStatus.Waiting)
            {
                // Return result to calling dialog
                return(await EndComponentAsync(outerDc, turnResult.Result, cancellationToken).ConfigureAwait(false));
            }
            else
            {
                // Just signal waiting
                return(Dialog.EndOfTurn);
            }
        }
Esempio n. 4
0
        private static DialogState InitializeDialogState(DialogInstance instance)
        {
            var dialogState = new DialogState();

            instance.State[PersistedDialogState] = dialogState;
            return(dialogState);
        }
Esempio n. 5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DialogContext"/> class.
 /// </summary>
 /// <param name="dialogs">Parent dialog set.</param>
 /// <param name="parentDialogContext">Parent dialog state.</param>
 /// <param name="state">Current dialog state.</param>
 public DialogContext(
     DialogSet dialogs,
     DialogContext parentDialogContext,
     DialogState state)
     : this(dialogs, parentDialogContext.Context, state)
 {
     Parent = parentDialogContext ?? throw new ArgumentNullException(nameof(parentDialogContext));
 }
Esempio n. 6
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DialogContext"/> class from the turn context.
        /// </summary>
        /// <param name="dialogs">The dialog set to create the dialog context for.</param>
        /// <param name="turnContext">The current turn context.</param>
        /// <param name="state">The state property from which to retrieve the dialog context.</param>
        public DialogContext(DialogSet dialogs, ITurnContext turnContext, DialogState state)
        {
            Dialogs = dialogs ?? throw new ArgumentNullException(nameof(dialogs));
            Context = turnContext ?? throw new ArgumentNullException(nameof(turnContext));
            Stack   = state.DialogStack;

            ObjectPath.SetPathValue(turnContext.TurnState, TurnPath.ACTIVITY, Context.Activity);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DialogContext"/> class from Turn context.
        /// </summary>
        /// <param name="dialogs">dialogset.</param>
        /// <param name="turnContext">turn context.</param>
        /// <param name="state">dialogState.</param>
        public DialogContext(DialogSet dialogs, ITurnContext turnContext, DialogState state)
        {
            Dialogs = dialogs ?? throw new ArgumentNullException(nameof(dialogs));
            Context = turnContext ?? throw new ArgumentNullException(nameof(turnContext));
            Stack   = state.DialogStack;
            State   = new DialogStateManager(this);

            State.SetValue(TurnPath.ACTIVITY, Context.Activity);
        }
        /// <summary>
        /// Runs dialog system in the context of an ITurnContext.
        /// </summary>
        /// <param name="context">turn context.</param>
        /// <param name="cancellationToken">cancelation token.</param>
        /// <returns>result of the running the logic against the activity.</returns>
        public async Task <DialogManagerResult> OnTurnAsync(ITurnContext context, CancellationToken cancellationToken = default(CancellationToken))
        {
            ConversationState conversationState = context.TurnState.Get <ConversationState>() ?? throw new ArgumentNullException($"{nameof(ConversationState)} is not found in the turn context. Have you called adapter.UseState() with a configured ConversationState object?");
            UserState         userState         = context.TurnState.Get <UserState>() ?? throw new ArgumentNullException($"{nameof(UserState)} is not found in the turn context. Have you called adapter.UseState() with a configured UserState object?");

            // create property accessors
            var lastAccessProperty = conversationState.CreateProperty <DateTime>(LASTACCESS);
            var lastAccess         = await lastAccessProperty.GetAsync(context, () => DateTime.UtcNow, cancellationToken : cancellationToken).ConfigureAwait(false);

            // Check for expired conversation
            var now = DateTime.UtcNow;

            if (this.ExpireAfter.HasValue && (DateTime.UtcNow - lastAccess) >= TimeSpan.FromMilliseconds((double)this.ExpireAfter))
            {
                // Clear conversation state
                await conversationState.ClearStateAsync(context, cancellationToken : cancellationToken).ConfigureAwait(false);
            }

            lastAccess = DateTime.UtcNow;
            await lastAccessProperty.SetAsync(context, lastAccess, cancellationToken : cancellationToken).ConfigureAwait(false);

            // get dialog stack
            var         dialogsProperty = conversationState.CreateProperty <DialogState>(DIALOGS);
            DialogState dialogState     = await dialogsProperty.GetAsync(context, () => new DialogState(), cancellationToken : cancellationToken).ConfigureAwait(false);

            // Create DialogContext
            var dc = new DialogContext(this.dialogSet, context, dialogState);

            DialogTurnResult turnResult = null;

            if (dc.ActiveDialog == null)
            {
                // start root dialog
                turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
            }
            else
            {
                // Continue execution
                // - This will apply any queued up interruptions and execute the current/next step(s).
                turnResult = await dc.ContinueDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false);

                if (turnResult.Status == DialogTurnStatus.Empty)
                {
                    // restart root dialog
                    turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
                }
            }

            // send trace of memory
            await dc.Context.SendActivityAsync((Activity)Activity.CreateTraceActivity("BotState", "https://www.botframework.com/schemas/botState", dc.GetState().GetMemorySnapshot(), "Bot State")).ConfigureAwait(false);

            return(new DialogManagerResult()
            {
                TurnResult = turnResult
            });
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DialogContext"/> class from the turn context.
        /// </summary>
        /// <param name="dialogs">The dialog set to create the dialog context for.</param>
        /// <param name="turnContext">The current turn context.</param>
        /// <param name="state">The state property from which to retrieve the dialog context.</param>
        public DialogContext(DialogSet dialogs, ITurnContext turnContext, DialogState state)
        {
            Dialogs  = dialogs ?? throw new ArgumentNullException(nameof(dialogs));
            Context  = turnContext ?? throw new ArgumentNullException(nameof(turnContext));
            Stack    = state.DialogStack;
            State    = new DialogStateManager(this);
            Services = new TurnContextStateCollection();

            ObjectPath.SetPathValue(turnContext.TurnState, TurnPath.Activity, Context.Activity);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DialogContext"/> class.
        /// </summary>
        /// <param name="dialogs">Parent dialog set.</param>
        /// <param name="parentDialogContext">Parent dialog context.</param>
        /// <param name="state">Current dialog state.</param>
        public DialogContext(
            DialogSet dialogs,
            DialogContext parentDialogContext,
            DialogState state)
            : this(dialogs, parentDialogContext.Context, state)
        {
            Parent = parentDialogContext ?? throw new ArgumentNullException(nameof(parentDialogContext));

            if (Parent.Services != null)
            {
                // copy parent services into this dialogcontext.
                foreach (var service in Parent.Services)
                {
                    Services[service.Key] = service.Value;
                }
            }
        }
Esempio n. 11
0
        private DialogContext CreateInnerDc(ITurnContext context, DialogInstance instance)
        {
            DialogState state;

            if (instance.State.ContainsKey(PersistedDialogState))
            {
                state = instance.State[PersistedDialogState] as DialogState;
            }
            else
            {
                state = new DialogState();
                instance.State[PersistedDialogState] = state;
            }

            if (state.DialogStack == null)
            {
                state.DialogStack = new List <DialogInstance>();
            }

            return(new DialogContext(this.Dialogs, context, state));
        }
        private static DialogState BuildDialogState(DialogInstance instance)
        {
            DialogState state;

            if (instance.State.ContainsKey(PersistedDialogState))
            {
                state = instance.State[PersistedDialogState] as DialogState;
            }
            else
            {
                state = new DialogState();
                instance.State[PersistedDialogState] = state;
            }

            if (state.DialogStack == null)
            {
                state.DialogStack = new List <DialogInstance>();
            }

            return(state);
        }
        /// <summary>
        /// Runs dialog system in the context of an ITurnContext.
        /// </summary>
        /// <param name="context">turn context.</param>
        /// <param name="cancellationToken">cancelation token.</param>
        /// <returns>result of the running the logic against the activity.</returns>
        public async Task <DialogManagerResult> OnTurnAsync(ITurnContext context, CancellationToken cancellationToken = default(CancellationToken))
        {
            var botStateSet = new BotStateSet();

            // preload turnstate with DM turnstate
            foreach (var pair in this.TurnState)
            {
                context.TurnState.Set(pair.Key, pair.Value);
            }

            if (this.ConversationState == null)
            {
                this.ConversationState = context.TurnState.Get <ConversationState>() ?? throw new ArgumentNullException(nameof(this.ConversationState));
            }
            else
            {
                context.TurnState.Set(this.ConversationState);
            }

            botStateSet.Add(this.ConversationState);

            if (this.UserState == null)
            {
                this.UserState = context.TurnState.Get <UserState>();
            }

            if (this.UserState != null)
            {
                botStateSet.Add(this.UserState);
            }

            // create property accessors
            var lastAccessProperty = ConversationState.CreateProperty <DateTime>(LASTACCESS);
            var lastAccess         = await lastAccessProperty.GetAsync(context, () => DateTime.UtcNow, cancellationToken : cancellationToken).ConfigureAwait(false);

            // Check for expired conversation
            var now = DateTime.UtcNow;

            if (this.ExpireAfter.HasValue && (DateTime.UtcNow - lastAccess) >= TimeSpan.FromMilliseconds((double)this.ExpireAfter))
            {
                // Clear conversation state
                await ConversationState.ClearStateAsync(context, cancellationToken : cancellationToken).ConfigureAwait(false);
            }

            lastAccess = DateTime.UtcNow;
            await lastAccessProperty.SetAsync(context, lastAccess, cancellationToken : cancellationToken).ConfigureAwait(false);

            // get dialog stack
            var         dialogsProperty = ConversationState.CreateProperty <DialogState>(this.dialogStateProperty);
            DialogState dialogState     = await dialogsProperty.GetAsync(context, () => new DialogState(), cancellationToken : cancellationToken).ConfigureAwait(false);

            // Create DialogContext
            var dc = new DialogContext(this.Dialogs, context, dialogState);

            // get the dialogstatemanager configuration
            var dialogStateManager = new DialogStateManager(dc, this.StateConfiguration);
            await dialogStateManager.LoadAllScopesAsync(cancellationToken).ConfigureAwait(false);

            dc.Context.TurnState.Add(dialogStateManager);

            DialogTurnResult turnResult = null;

            // Loop as long as we are getting valid OnError handled we should continue executing the actions for the turn.
            //
            // NOTE: We loop around this block because each pass through we either complete the turn and break out of the loop
            // or we have had an exception AND there was an OnError action which captured the error.  We need to continue the
            // turn based on the actions the OnError handler introduced.
            while (true)
            {
                try
                {
                    if (dc.ActiveDialog == null)
                    {
                        // start root dialog
                        turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        // Continue execution
                        // - This will apply any queued up interruptions and execute the current/next step(s).
                        turnResult = await dc.ContinueDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false);

                        if (turnResult.Status == DialogTurnStatus.Empty)
                        {
                            // restart root dialog
                            turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
                        }
                    }

                    // turn successfully completed, break the loop
                    break;
                }
                catch (Exception err)
                {
                    // fire error event, bubbling from the leaf.
                    var handled = await dc.EmitEventAsync(DialogEvents.Error, err, bubble : true, fromLeaf : true, cancellationToken : cancellationToken).ConfigureAwait(false);

                    if (!handled)
                    {
                        // error was NOT handled, throw the exception and end the turn. (This will trigger the Adapter.OnError handler and end the entire dialog stack)
                        throw;
                    }
                }
            }

            // save all state scopes to their respective botState locations.
            await dialogStateManager.SaveAllChangesAsync(cancellationToken).ConfigureAwait(false);

            // save botstate changes
            await botStateSet.SaveAllChangesAsync(dc.Context, false, cancellationToken).ConfigureAwait(false);

            // send trace of memory
            var snapshot      = dc.GetState().GetMemorySnapshot();
            var traceActivity = (Activity)Activity.CreateTraceActivity("BotState", "https://www.botframework.com/schemas/botState", snapshot, "Bot State");
            await dc.Context.SendActivityAsync(traceActivity).ConfigureAwait(false);

            return(new DialogManagerResult()
            {
                TurnResult = turnResult
            });
        }
Esempio n. 14
0
        /// <summary>
        /// Runs dialog system in the context of an ITurnContext.
        /// </summary>
        /// <param name="context">turn context.</param>
        /// <param name="state">stored state.</param>
        /// <param name="cancellationToken">cancelation token.</param>
        /// <returns>result of the running the logic against the activity.</returns>
        public async Task <DialogManagerResult> OnTurnAsync(ITurnContext context, PersistedState state = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            var saveState = false;
            var keys      = GetKeys(context);
            var storage   = context.TurnState.Get <IStorage>();

            if (state == null)
            {
                if (storage == null)
                {
                    throw new Exception("DialogManager: unable to load the bots state.Bot.storage not assigned.");
                }

                state = await LoadStateAsync(storage, keys).ConfigureAwait(false);

                saveState = true;
            }

            // Clone state to preserve original state
            var newState = ObjectPath.Clone(state);

            // Check for expired conversation
            var now = DateTime.UtcNow;

            if (this.ExpireAfter.HasValue && newState.ConversationState.ContainsKey(LASTACCESS))
            {
                var lastAccess = DateTime.Parse(newState.ConversationState[LASTACCESS] as string);
                if ((DateTime.UtcNow - lastAccess) >= TimeSpan.FromMilliseconds((double)this.ExpireAfter))
                {
                    // Clear conversation state
                    state.ConversationState       = new Dictionary <string, object>();
                    state.ConversationState[ETAG] = newState.ConversationState[ETAG];
                }
            }

            newState.ConversationState[LASTACCESS] = DateTime.UtcNow.ToString("u");

            // Ensure dialog stack populated
            DialogState dialogState;

            if (!newState.ConversationState.ContainsKey(DIALOGS))
            {
                dialogState = new DialogState();
                newState.ConversationState[DIALOGS] = dialogState;
            }
            else
            {
                dialogState = (DialogState)newState.ConversationState[DIALOGS];
            }

            var namedScopes = MemoryScope.GetScopesMemory(context);

            namedScopes[ScopePath.USER]         = newState.UserState;
            namedScopes[ScopePath.CONVERSATION] = newState.ConversationState;
            namedScopes[ScopePath.TURN]         = new Dictionary <string, object>(StringComparer.InvariantCultureIgnoreCase);

            // Create DialogContext
            var dc = new DialogContext(
                this.dialogSet,
                context,
                dialogState);

            DialogTurnResult turnResult = null;

            if (dc.ActiveDialog == null)
            {
                // start root dialog
                turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
            }
            else
            {
                // Continue execution
                // - This will apply any queued up interruptions and execute the current/next step(s).
                turnResult = await dc.ContinueDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false);

                if (turnResult.Status == DialogTurnStatus.Empty)
                {
                    // restart root dialog
                    turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
                }
            }

            // send trace of memory
            await dc.Context.SendActivityAsync((Activity)Activity.CreateTraceActivity("BotState", "https://www.botframework.com/schemas/botState", dc.State.GetMemorySnapshot(), "Bot State")).ConfigureAwait(false);

            // Save state if loaded from storage
            if (saveState)
            {
                await DialogManager.SaveStateAsync(storage, keys : keys, newState : newState, oldState : state, eTag : "*").ConfigureAwait(false);

                return(new DialogManagerResult()
                {
                    TurnResult = turnResult
                });
            }
            else
            {
                return(new DialogManagerResult()
                {
                    TurnResult = turnResult, NewState = newState
                });
            }
        }