How do I intercept a message in FormFlow before it

2019-09-02 14:33发布

I would like to intercept what the user writes if he doesn't like any option in the list. My code is the following, but the validate function works only if the user chooses an option.

using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.FormFlow;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;


namespace BotApplication.App_Code
{
    public enum MainOptions { AccessoAreaRiservata = 1, AcquistoNuovaPolizza, RinnovoPolizza, Documenti, StatoPratica, AltroArgomento }

    [Serializable]
    public class MainReq
    {
        [Prompt("Indicare la tipologia della richiesta? {||}")]
        public MainOptions? MainOption;

        public static IForm<MainReq> BuildForm()
        {
            var form = (new FormBuilder<MainReq>()

                .Field(nameof(MainOption),validate: async (state, response) =>
                        {
                            var result = new ValidateResult { IsValid = true };
                          {
                            string risposta = (response.ToString());
                            if (risposta  == "AltroArgomento")
                            {
                                result.Feedback = "it works only if user choose an option";
                                result.IsValid = true;
                            }
                            return result;
                          }
                        })
                .Build()); 
            return form;
        }
    }
}

1条回答
Evening l夕情丶
2楼-- · 2019-09-02 15:22

There are a few possible workarounds for you to consider. Normally if you want to account for situations where a user wants to ask a question or say something unrelated to the form, you'd have them cancel the form using the Quit command. If you want your bot to be smart enough to interpret when users change the subject in the middle of a form, that's a bit more advanced.

If you want to keep using a validate method, you can change your MainOption field to a string instead of a MainOptions? so that all user input gets sent to the validate method, but then you'd need to generate the list of choices yourself.

My recommendation is to use a custom prompter instead of a validate method. I've written a blog post that details how to make such a prompter. First you would provide a NotUnderstood template to indicate to your prompter when a message isn't a valid option in FormFlow. Then in the prompter you would call your QnAMaker dialog or do whatever you want with the message.

// Define your NotUnderstood template
[Serializable, Template(TemplateUsage.NotUnderstood, NOT_UNDERSTOOD)]
public class MainReq
{
    public const string NOT_UNDERSTOOD = "Not-understood message";

    [Prompt("Indicare la tipologia della richiesta? {||}")]
    public MainOptions? MainOption;

    public static IForm<MainReq> BuildForm()
    {
        var form = (new FormBuilder<MainReq>()
            .Prompter(PromptAsync)  // Build your form with a custom prompter
            .Build());

        return form;
    }

    private static async Task<FormPrompt> PromptAsync(IDialogContext context, FormPrompt prompt, MainReq state, IField<MainReq> field)
    {
        var preamble = context.MakeMessage();
        var promptMessage = context.MakeMessage();

        if (prompt.GenerateMessages(preamble, promptMessage))
        {
            await context.PostAsync(preamble);
        }

        // Here is where we've made a change to the default prompter.
        if (promptMessage.Text == NOT_UNDERSTOOD)
        {
            // Access the message the user typed with context.Activity
            await context.PostAsync($"Do what you want with the message: {context.Activity.AsMessageActivity()?.Text}");
        }
        else
        {
            await context.PostAsync(promptMessage);
        }

        return prompt;
    }
}
查看更多
登录 后发表回答