feili
feili

Reputation: 1

How to pass outer state to dialog when it starts?

For instance, I have a state containing a city name, and I store it in a conversation state.

When I start the dialog, the dialog asks the users for the name of the city and ends the dialog.

In next turn, the dialog starts again but I wish this time the dialog has already got the city name from the outer scope, instead of asking the user again.

I know waterfall dialog could do it, every step could get the result from the last step. But I want to know how to achieve it between dialogs.

Please show me more details and samples. Thanks! My questions is similar to this question.

Upvotes: 0

Views: 56

Answers (1)

ashmit-001
ashmit-001

Reputation: 402

You need to save your state each time user enters some message.

First generate state variables in BotStateService.cs.

And inside DialogBot.cs, each time user enters a message it willl go in OnTurnAsync method, save your state there.

You can try this way out.

BotStateService.cs :

namespace CoreBot.Services
{
    public class BotStateService
    {
        //state variables
        public UserState _userState { get; }
        public ConversationState _conversationState { get; }
        public DialogState _dialogState { get; }

        //IDs
        public static string UserProfileId { get; } = $"{nameof(BotStateService)}.UserProfile";
        public static string ConversationDataId { get; } = $"{nameof(ConversationState)}.ConversationData";
        public static string DialogStateId { get; } = $"{nameof(DialogState)}.DialogState";

        //Accessors
        public IStatePropertyAccessor<UserProfile> UserProfileAccessors { get; set; }
        public IStatePropertyAccessor<ConversationData> ConversationDataAccessors { get; set; }
        public IStatePropertyAccessor<DialogState> DialogStateAccessors { get; set; }


        public BotStateService(UserState userState, ConversationState conversationState)
        {
            _userState = userState ?? throw new ArgumentNullException(nameof(userState));
            _conversationState = conversationState ?? throw new ArgumentNullException(nameof(conversationState));

            InitializeAccessors();
        }

        private void InitializeAccessors()
        {
            UserProfileAccessors = _userState.CreateProperty<UserProfile>(UserProfileId);

            ConversationDataAccessors = _conversationState.CreateProperty<ConversationData>(ConversationDataId);
            DialogStateAccessors = _conversationState.CreateProperty<DialogState>(DialogStateId);

        }
    }
}

DialogBot.cs :

    public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default)
            {
// Save your state each time user enters the conversation or enters a message
                await base.OnTurnAsync(turnContext, cancellationToken);
                await _botStateService._userState.SaveChangesAsync(turnContext);
                await _botStateService._conversationState.SaveChangesAsync(turnContext);
    }

GreetingDialog.cs :

    private async Task<DialogTurnResult> InitialStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
            {

                UserProfile userProfile = await _botStateService.UserProfileAccessors.GetAsync(stepContext.Context, () => new UserProfile());

                    if (String.IsNullOrEmpty(userProfile.city))
                    {
                        return await stepContext.PromptAsync($"{nameof(GreetingDialog)}.city",
                            new PromptOptions
                            {
                                Prompt = MessageFactory.Text("Please tell me name of your city.")
                            }, cancellationToken);
                    }
                    else
                    {
                        return await stepContext.NextAsync(null, cancellationToken);
                    }
            }

private async Task<DialogTurnResult> FinalStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{

UserProfile userProfile = await _botStateService.UserProfileAccessors.GetAsync(stepContext.Context, () => new UserProfile());
                if (String.IsNullOrEmpty(userProfile.city))
                {
                    userProfile.city = (String)stepContext.Result;
                    await _botStateService.UserProfileAccessors.SetAsync(stepContext.Context, userProfile);
                }

return await stepContext.EndDialogAsync(null, cancellationToken);
}

UserProfile.cs :

using System;

    namespace CoreBot.Profiles
    {
        public class UserProfile
        {

            public string city { get; set; }
        }
    }

Hope this helps! Ask in case of any query.

Upvotes: 1

Related Questions