Create Bot for Microsoft Graph with DevOps 9: BotBuilder features – FormFlow 101

DialogPrompt is great, but if you want to simply create a form, then FormFlow is the one you want to use.

Create a form by using FormFlow

FormFlow uses model to create a form.

Add model

1. Open O365Bot solution and add Models folder.

image

2. Add OutlookEvent.cs and replace the code. Don’t forget to add Serializable attribute.

using System;

namespace O365Bot.Models
{
    [Serializable]
    public class OutlookEvent
    {
        public string Subject { get; set; }
        public string Description { get; set; }
        public DateTime Start { get; set; }
        public bool IsAllDay { get; set; }
        public double Hours { get; set; }
    }
}

Update CreateDialog.cs

Now use the model you just added to generate a form. Replace the code with following. As you can see, you need less lines.

using Autofac;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.FormFlow;
using Microsoft.Graph;
using O365Bot.Models;
using O365Bot.Services;
using System;
using System.Threading.Tasks;

namespace O365Bot.Dialogs
{
    [Serializable]
    public class CreateEventDialog : IDialog<bool> 
    {
        public async Task StartAsync(IDialogContext context)
        {
            // Create a from
            var outlookEventFormDialog = FormDialog.FromForm(this.BuildOutlookEventForm, FormOptions.PromptInStart);
            context.Call(outlookEventFormDialog, this.ResumeAfterDialog);
        }

        private async Task ResumeAfterDialog(IDialogContext context, IAwaitable<OutlookEvent> result)
        {
            await context.PostAsync("The event is created.");

            // Complete the child dialog.
            context.Done(true);
        }

        private IForm<OutlookEvent> BuildOutlookEventForm()
        {
            OnCompletionAsyncDelegate<OutlookEvent> processOutlookEventCreate = async (context, state) =>
            {
                using (var scope = WebApiApplication.Container.BeginLifetimeScope())
                {
                    IEventService service = scope.Resolve<IEventService>(new TypedParameter(typeof(IDialogContext), context));
                    Event @event = new Event()
                    {
                        Subject = state.Subject,
                        Start = new DateTimeTimeZone() { DateTime = state.Start.ToString(), TimeZone = "Tokyo Standard Time" },
                        IsAllDay = state.IsAllDay,
                        End = state.IsAllDay ? null : new DateTimeTimeZone() { DateTime = state.Start.AddHours(state.Hours).ToString(), TimeZone = "Tokyo Standard Time" },
                        Body = new ItemBody() { Content = state.Description, ContentType = BodyType.Text }
                    };
                    await service.CreateEvent(@event);
                }
            };

            return new FormBuilder<OutlookEvent>()
                .Message("Creating an event.")
                .AddRemainingFields() // add all (remaing) fields to the form.
                .OnCompletion(processOutlookEventCreate)
                .Build();
        }
    }
}

Try with emulator

Run the application and connect to the server via emulator.

image

Everything seems okay, but let’s modify the display string.

FormFlow attributes for Model

There are several places where you can change the display string. This time, specify Prompt attribute to model. Replace the code in OutlookEvent.cs, You can use pattern language such as {||} to let user select from options as part of Prompt. See here for more detail.

using Microsoft.Bot.Builder.FormFlow;
using System;

namespace O365Bot.Models
{
    [Serializable]
    public class OutlookEvent
    {
        [Prompt("What is the title?")]
        public string Subject { get; set; }
        [Prompt("What is the detail?")]
        public string Description { get; set; }
        [Prompt("When do you start? Use dd/MM/yyyy HH:mm format.")]
        public DateTime Start { get; set; }
        [Prompt("Is this all day event?{||}")]
        public bool IsAllDay { get; set; }
        [Prompt("How many hours?", "Please answer by number")]
        public double Hours { get; set; }
    }
}

Try with emulator

Run the application and connect to the server via emulator.

image

Now it looks work exactly same as last article. However, several test shall fail.

image

Summery

FormFlow is so easy to create a form, but you can do more. Next time, I will explain more detailed features and make all test pass.

GitHub: https://github.com/kenakamu/BotWithDevOps-Blog-sample/tree/master/article9

Ken