Reputation: 1
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
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