internal static async Task <DialogTurnResult> InternalRunAsync(ITurnContext turnContext, string dialogId, DialogContext dialogContext, DialogStateManagerConfiguration stateConfiguration, CancellationToken cancellationToken)
        {
            // map TurnState into root dialog context.services
            foreach (var service in turnContext.TurnState)
            {
                dialogContext.Services[service.Key] = service.Value;
            }

            var dialogStateManager = new DialogStateManager(dialogContext, stateConfiguration);
            await dialogStateManager.LoadAllScopesAsync(cancellationToken).ConfigureAwait(false);

            dialogContext.Context.TurnState.Add(dialogStateManager);

            DialogTurnResult dialogTurnResult = 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.
            var endOfTurn = false;

            while (!endOfTurn)
            {
                try
                {
                    dialogTurnResult = await InnerRunAsync(turnContext, dialogId, dialogContext, cancellationToken).ConfigureAwait(false);

                    // turn successfully completed, break the loop
                    endOfTurn = true;
                }
                catch (Exception err)
                {
                    // fire error event, bubbling from the leaf.
                    var handled = await dialogContext.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);

            // return the redundant result because the DialogManager contract expects it
            return(dialogTurnResult);
        }
        /// <summary>
        /// CheckForVersionChangeAsync.
        /// </summary>
        /// <param name="dc">dialog context.</param>
        /// <param name="cancellationToken">cancellationToken.</param>
        /// <returns>task.</returns>
        /// <remarks>
        /// Checks to see if a containers child dialogs have changed since the current dialog instance
        /// was started.
        ///
        /// This should be called at the start of `beginDialog()`, `continueDialog()`, and `resumeDialog()`.
        /// </remarks>
        protected virtual async Task CheckForVersionChangeAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var current = dc.ActiveDialog.Version;

            dc.ActiveDialog.Version = this.GetInternalVersion();

            // Check for change of previously stored hash
            if (current != null && current != dc.ActiveDialog.Version)
            {
                // Give bot an opportunity to handle the change.
                // - If bot handles it the changeHash will have been updated as to avoid triggering the
                //   change again.
                await dc.EmitEventAsync(DialogEvents.VersionChanged, this.Id, true, false, cancellationToken).ConfigureAwait(false);
            }
        }
        /// <summary>
        /// CheckForVersionChangeAsync.
        /// </summary>
        /// <param name="dc">dialog context.</param>
        /// <returns>task.</returns>
        /// <remarks>
        /// Checks to see if a containers child dialogs have changed since the current dialog instance
        /// was started.
        ///
        /// This should be called at the start of `beginDialog()`, `continueDialog()`, and `resumeDialog()`.
        /// </remarks>
        protected virtual async Task CheckForVersionChangeAsync(DialogContext dc)
        {
            var current = dc.ActiveDialog.Version;

            dc.ActiveDialog.Version = this.GetInternalVersion();

            // Check for change of previously stored hash
            if (current != null && current != dc.ActiveDialog.Version)
            {
                // Give bot an opportunity to handle the change.
                // - If bot handles it the changeHash will have been updated as to avoid triggering the
                //   change again.
                var handled = await dc.EmitEventAsync(DialogEvents.VersionChanged, this.Id, true, false).ConfigureAwait(false);

                if (!handled)
                {
                    // Throw an error for bot to catch
                    throw new Exception($"Version change detected for '{this.Id}' dialog.");
                }
            }
        }
        /// <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
            });
        }