I am working with the DialogPromptBot sample. In the sample there is the following code:
// Create the dialog set and add the prompts, including custom validation.
_dialogSet = new DialogSet(_accessors.DialogStateAccessor);
_dialogSet.Add(new NumberPrompt<int>(PartySizePrompt, PartySizeValidatorAsync));
_dialogSet.Add(new ChoicePrompt(LocationPrompt));
_dialogSet.Add(new DateTimePrompt(ReservationDatePrompt, DateValidatorAsync));
// Define the steps of the waterfall dialog and add it to the set.
WaterfallStep[] steps = new WaterfallStep[]
{
PromptForPartySizeAsync,
PromptForLocationAsync,
PromptForReservationDateAsync,
AcknowledgeReservationAsync,
};
_dialogSet.Add(new WaterfallDialog(ReservationDialog, steps));
It sets up some prompts, validates the user's input and saves their responses. I don't like the way the code works because the user's input is saved in the next step (i.e., the party size is saved in the prompt for a location and the location is saved in the prompt for date). I would like to save the user's input in the corresponding validation step. This would remove the entanglement between requests and allow me to reorder the questions without making a lot of extraneous changes. It would also allow me to use the same validator for questions of the same type.
How do I access the WaterfallStepContext
from the Prompt Validator? This would allow me to save the user's input once I determined that it was valid. In addition, the ChoicePrompt
is supposed to take a Prompt Validator as well but I can't seem to get that to work. It seems to have built-in validation but I would also like to save the user's input there as well.
It is not recommended to store any state when performing validation of a prompt value. Instead it should be the responsibility of the caller of the prompt to do something with that value. Specifically, when using WaterfallDialog
, the pattern that is recommended is that the "next" step is always responsible for storing the result of the previous step.
So imagine having a number prompt that ensures a value between 1 and 100 is picked:
Add(new NumberPrompt<int>("myNumberPrompt", async (pvc, ct) => pvc.Succeeded && pvc.Recognized.Value > 1 && pvc.Recognized.Value < 100);
And then some waterfall steps that utilize that prompt:
private async Task<DialogTurnResult> FirstStep(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
return await stepContext.PromptAsync("myNumberPrompt", new PromptOptions { Prompt = MessageFactory.Text("Please pick a number between 1 and 100") }, cancellationToken);
}
private async Task<DialogTurnResult> SecondStep(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
// Get the result of the previous step which will be the value from the NumberPrompt<int>
var chosenNumber = (int)stepContext.Result;
// Store the value into the WaterfallStepContext's Values dictionary
stepContext.Values["ChosenNumber"] = chosenNumber;
await stepContext.Context.SendActivityAsync($"Ok, {chosenNumber}, got it.");
// ... more code here, maybe prompt for other values, whatever ...
}