I have the following scenario I think I'm doing it wrong.
I have a RootDialog
which calls a ResultDialog
. The ResultDialog
presents the user a list of results (using HeroCard
).
The ResultDialog closes itself using context.Done(..)
after the message was posted.
In the RootDialog- AfterResultDialog
Resume handler I want to ask the user if he has found the matching result, using another dialog (NotificationDialog
), but I want to do that after 30 seconds.
After some research, this seems like it must be done using proactive messages.
It this example, I found a way to post the NotificationDialog
in a proactive way.
private async Task AfterResultDialog(IDialogContext context, IAwaitable<object> result)
{
var message = await result as IMessageActivity;
var conversationReference = context.Activity.ToConversationReference();
ConversationStarter.conversationReference = JsonConvert.SerializeObject(conversationReference);
t = new Timer(timerEvent);
t.Change(30000, Timeout.Infinite);
context.Wait<string>(NotificationDialogAfter);
}
public void timerEvent(object target)
{
t.Dispose();
ConversationStarter.Resume();
}
But the problem I have is that I'm interested in the result of this NotifcationDialog
to know what the user wants to do next.
But all examples I found using proactive-messages do not regard the result of a proactive message with dialog:
public class ConversationStarter
{
public static string conversationReference;
public static async Task Resume()
{
var message = JsonConvert.DeserializeObject<ConversationReference>(conversationReference).GetPostToBotMessage();
var client = new ConnectorClient(new Uri(message.ServiceUrl));
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(CancellationToken.None);
var task = scope.Resolve<IDialogTask>();
// here it seems only to be possible to call a dialog using Void
var dialog = new NotificationDialog();
task.Call(dialog.Void<object, IMessageActivity>(), null);
await task.PollAsync(CancellationToken.None);
await botData.FlushAsync(CancellationToken.None);
}
}
}
The NotificationDialogAfter
handler should decide based on the user input which dialog to call next:
private async Task NotificationDialogAfter(IDialogContext context, IAwaitable<string> result)
{
var whereToContinue = await result;
if (whereToContinue.Equals("Start over"))
{
context.ClearAllConversationDataKeys();
context.Call(new TagDialog(), this.TagDialogAfter);
}
else if (whereToContinue == "Tell friends")
{
context.Call(new TellFriendsDialog(), TellFriendsDialogAfter);
}
else if (whereToContinue == "Feedback")
{
context.Call(new FeedbackDialog(), this.FeedbackDialogAfter);
}
}
So what I basically want is that the result of the NotificationDialog
is forwarded to the NotificationDialogAfter
handler which the Root dialog is waiting for.
Is this even possible?
I solve the problem by defining static continue handlers (in GlobalContinueHandler
), that I can provide inside the NotificationDialog, when calling other dialogs.
[Serializable]
public class NotificationDialog : IDialog<string>
{
public Task StartAsync(IDialogContext context)
{
PromptDialog.Choice(context, Resume, new List<string> { "yes", "no" },
"Found what you're looking for?");
return Task.CompletedTask;
}
private async Task Resume(IDialogContext context, IAwaitable<string> result)
{
var message = await result;
if (message == "yes")
{
context.Call(new SignupDialog(), GlobalContinueHandler.SignupDialogAfter);
}
else
{
context.Call(new FeedbackDialog(), GlobalContinueHandler.FeedbackDialogAfter);
}
}
}
I'm really not fan of this solution but for now it seems to work.