Take a close look at sample 45.state-management from the Botbuilder-Samples repo. It demonstrates how you can reference a set value in state to determine dialog flow. It would also be good for you to read over the "Save user and conversation data" doc, located here.
In short, you will need to do the following:
In the Startup.cs file, add the following. Be prepared to configure to meet your needs.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<ICredentialProvider, ConfigurationCredentialProvider>();
services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
services.AddSingleton<IStorage, MemoryStorage>();
services.AddSingleton<UserState>();
services.AddSingleton<ConversationState>();
services.AddTransient<IBot, StateManagementBot>();
}
}
In your "bot.cs" file, do the following. Again, this is an example, so tailor to your needs. First, set the state objects (_conversationState, _userState). Once that is done, you can set and recall state values according to the dialog flow using those value to help drive the next action. In this example, state is being referenced in order to determine if a user's name should be asked for again, or not.
namespace Microsoft.BotBuilderSamples
{
public class StateManagementBot : ActivityHandler
{
private BotState _conversationState;
private BotState _userState;
public StateManagementBot(ConversationState conversationState, UserState userState)
{
_conversationState = conversationState;
_userState = userState;
}
public override async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
await base.OnTurnAsync(turnContext, cancellationToken);
await _conversationState.SaveChangesAsync(turnContext, false, cancellationToken);
await _userState.SaveChangesAsync(turnContext, false, cancellationToken);
}
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
await turnContext.SendActivityAsync("Welcome to State Bot Sample. Type anything to get started.");
}
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
var conversationStateAccessors = _conversationState.CreateProperty<ConversationData>(nameof(ConversationData));
var conversationData = await conversationStateAccessors.GetAsync(turnContext, () => new ConversationData());
var userStateAccessors = _userState.CreateProperty<UserProfile>(nameof(UserProfile));
var userProfile = await userStateAccessors.GetAsync(turnContext, () => new UserProfile());
if (string.IsNullOrEmpty(userProfile.Name))
{
if (conversationData.PromptedUserForName)
{
userProfile.Name = turnContext.Activity.Text?.Trim();
await turnContext.SendActivityAsync($"Thanks {userProfile.Name}. To see conversation data, type anything.");
conversationData.PromptedUserForName = false;
}
else
{
await turnContext.SendActivityAsync($"What is your name?");
conversationData.PromptedUserForName = true;
}
}
else
{
var messageTimeOffset = (DateTimeOffset) turnContext.Activity.Timestamp;
var localMessageTime = messageTimeOffset.ToLocalTime();
conversationData.Timestamp = localMessageTime.ToString();
conversationData.ChannelId = turnContext.Activity.ChannelId.ToString();
await turnContext.SendActivityAsync($"{userProfile.Name} sent: {turnContext.Activity.Text}");
await turnContext.SendActivityAsync($"Message received at: {conversationData.Timestamp}");
await turnContext.SendActivityAsync($"Message received from: {conversationData.ChannelId}");
}
}
}
}
In this way, you can track whether a user has already visited a particular dialog. If the value is true, then the dialog is skipped and the user is redirected. Hope of help!