Search code examples
c#botframeworkchatbotazure-language-understanding

How to start a waterfall dialog from ActivityHandler.OnMessageActivityAsync in bot framework v4


I am trying to write a simple bot that will start my waterfall dialog when the user enter something. The usecase is very simple but it just doesn't seem to work, what is wrong?

The main bot is setup as such, I try to call my dialog in the OnMessageActivityAsync function:

namespace EmptyBot1.Dialogs
{
    public class MainChatbot : ActivityHandler
    {
        private readonly IOptions<Models.Configurations> _mySettings;
        protected readonly IRecognizer _recognizer;
        protected readonly BotState _conversationState;

        public MainChatbot(ConversationState conversationState, IOptions<Models.Configurations> mySettings, ChatbotRecognizer recognizer)
        {
            _mySettings = mySettings ?? throw new ArgumentNullException(nameof(mySettings));
            _recognizer = recognizer;
            _conversationState = conversationState;
        }

        protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            string LuisAppId = _mySettings.Value.LuisAppId;
            string LuisAPIKey = _mySettings.Value.LuisAPIKey;
            string LuisAPIHostName = _mySettings.Value.LuisAPIHostName;
            await turnContext.SendActivityAsync(MessageFactory.Text($"You Said: {turnContext.Activity.Text}"), cancellationToken);


            var luisResult = await _recognizer.RecognizeAsync<Models.ChatbotIntent>(turnContext, cancellationToken);
            Models.ChatbotIntent.Intent TopIntent = luisResult.TopIntent().intent;
            await turnContext.SendActivityAsync(MessageFactory.Text($"Your Intention Is: {TopIntent.ToString()}"), cancellationToken);

            switch (TopIntent)
            {
                case Models.ChatbotIntent.Intent.RunBot:
                    var RunBotOptions = new Models.RunBotOptions();
                    Dialog d = new MyCustomDialog();
                    // Trying to start my dialog here.
                    await d.RunAsync(turnContext, _conversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
                    break;
                default:
                    break;
            }
            return;
        }


    }
}

Then I setup my dialog like this, also simple enough:

namespace EmptyBot1.Dialogs
{
    public class MyCustomDialog : InteruptsDialog
    {
        public MyCustomDialog()
            : base(nameof(MyCustomDialog))
        {
            AddDialog(new TextPrompt(nameof(TextPrompt)));
            AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
            AddDialog(new WaterfallDialog(nameof(WaterfallDialog), new WaterfallStep[]
            {
                AskName,
                AskUseDefault,
                FinalStep
            }));

            // The initial child Dialog to run.
            InitialDialogId = nameof(WaterfallDialog);
        }
     // ...
    }
}

Everything is injected in startup.cs

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        // Add functionality to inject IOptions<T>
        services.AddOptions();

        // Add our Config object so it can be injected
        services.Configure<Models.Configurations>(Configuration);

        // Create the Bot Framework Adapter with error handling enabled.
        services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();

        // Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
        services.AddTransient<IBot, Dialogs.MainChatbot>();

        // Create the Conversation state. (Used by the Dialog system itself.)
        var storage = new MemoryStorage();
        var conversationState = new ConversationState(storage);
        services.AddSingleton(conversationState);



        // Register LUIS recognizer
        services.AddSingleton<ChatbotRecognizer>();

        services.AddSingleton<Dialogs.MyCustomDialog>();
    }

But when I run it I get 500 error, what am I doing wrong?

EDIT: To clarify, my goal is to be able to start a hardcoded waterfall dialog directly from ActivityHandler.OnMessageActivityAsync.

The general solution from online and from the example projects from Microsoft all say to pass the dialog as a type T to my bot.

However, I already know exactly which dialog to start so there is need to pass it as a type, I can just hardcode it directly inside the bot, how do I start it?


Solution

  • Turn out my code seem to work fine, not sure why it wasn't working yesterday. I'll leave it for future people checking up on answers. You can just use it exactly as it is in the question.