endDialogAsync() ends the current dialog on the stack returning control to the parent dialog, if present, or to the turn handler. Additionally, it can be called from anywhere the dialog context is accessible. Best practice is to call it at the end of every dialog.
The DOM Dialog close() method is used to close the dialog. The Dialog element is accessed by getElementById().
What is a dialog in Bot framework? Basically dialog is a class, which allows Bot developer to logically separate various areas of Bot functionality and guide conversational flow.
From my understanding of your question, what you want to achieve is to reset the dialog stack without completely destroy the bot state.
BotDataStore > BotData > DialogStack
Knowing FACTS from above, my solution will be
// in Global.asax.cs
var builder = new ContainerBuilder();
builder.RegisterModule(new DialogModule());
builder.RegisterModule(new ReflectionSurrogateModule());
builder.RegisterModule(new DialogModule_MakeRoot());
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
private static ILifetimeScope Container
{
get
{
var config = GlobalConfiguration.Configuration;
var resolver = (AutofacWebApiDependencyResolver)config.DependencyResolver;
return resolver.Container;
}
}
using (var scope = DialogModule.BeginLifetimeScope(Container, activity))
{
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(default(CancellationToken));
var stack = scope.Resolve<IDialogStack>();
stack.Reset();
await botData.FlushAsync(default(CancellationToken));
}
Hope it helps.
Thanks to @ejadib to point out, Container is already being exposed in conversation class.
We can remove step 2 in the answer above, in the end the code will look like
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
{
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(default(CancellationToken));
var stack = scope.Resolve<IDialogStack>();
stack.Reset();
await botData.FlushAsync(default(CancellationToken));
}
Here is a horribly ugly hack that works. It basically deletes all user data (which you might actually need) and this causes the conversation to restart.
If someone knows a better way, without deleting user data, please please share.
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
try
{
if (activity.Type == ActivityTypes.Message)
{
//if the user types certain messages, quit all dialogs and start over
string msg = activity.Text.ToLower().Trim();
if (msg == "start over" || msg == "exit" || msg == "quit" || msg == "done" || msg =="start again" || msg == "restart" || msg == "leave" || msg == "reset")
{
//This is where the conversation gets reset!
activity.GetStateClient().BotState.DeleteStateForUser(activity.ChannelId, activity.From.Id);
}
//and even if we reset everything, show the welcome message again
BotUtils.SendTyping(activity); //send "typing" indicator upon each message received
await Conversation.SendAsync(activity, () => new RootDialog());
}
else
{
HandleSystemMessage(activity);
}
}
I know this is a little old, but I had the same problem and the posted solutions are no longer the best approaches.
I'm not sure since what version this is available, but on 3.8.1 you can register IScorable
services that can be triggered anywhere in the dialog.
There is a sample code that shows how it works, and it does have a "cancel" global command handler:
https://github.com/Microsoft/BotBuilder-Samples/tree/master/CSharp/core-GlobalMessageHandlers
A part of the code will look like this:
protected override async Task PostAsync(IActivity item, string state, CancellationToken token)
{
this.task.Reset();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With