Tuesday, October 4, 2016

Microsoft Bot Builder .Net Using FormFlow: Real World Example of Product Registration - Part 4

In this part

  1. We will modify our Bot to work with real world example.
  2. We will create Bot that will ask use series of questions required to register product.
  3. We will also use validation to validate user input.

Lets Start

First we will have Registration Form in which we will have following fields required for registering any product.

  1. FirstName (string)
  2. LastName (string)
  3. Email (string, email)
  4. ModelNumber (string)
  5. DateOfPurchase (DateTime)
  6. State (Enum, {NSW, VIC, TAS, QLD, WA, NT})
  7. KeepMeUpdatedForProductsAndPromotions (bool)
Lets start by defining the classes

Registration Model


 [Serializable]
    public class RegistrationForm
    {
        public string FirstName { get; set; }

        public string LastName { get; set; }

        [Pattern(@"^\w+([\.+_])*\w+@\w+(\.\w+)+$")]
        [Template(TemplateUsage.NotUnderstood, "Email \"{0}\" is not valid.")]
        public string Email { get; set; }

        public string ModelNumber { get; set; }

        public DateTime DateOfPurchase { get; set; }

        [Prompt("At what {&} did you purchase product? {||}", ChoiceFormat = "{1}")]
        public List State { get; set; }
        [Describe("Whould you like to be keep updated regarding new products and promotions?")]
        public bool KeepMeUpdatedForProductsAndPromotions { get; set; }
       
    }

This is very simple model class to hold registration data.
This model defines basic properties together with these properties

  • We have used Pattern Attribute to validate email address through Regex.
  • We have used state enum to provide list to select from
  • We will use custom validation for Model number to validate the model number



Registration Form Builder Class


 [Serializable]
    public class RegistrationFormBuilder
    {

        public IForm BuildForm()
        {
            System.Net.ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;
 
             OnCompletionAsyncDelegate  processOrder = async (context, state) =>
            {
                var message = context.MakeMessage();
                message.Text = "Your registration has been successfull.";
                await context.PostAsync(message);
            };

     
            return new FormBuilder()
                    .Message("Welcome to the product registration bot!")
                    .Field(nameof(RegistrationForm.FirstName))
                    .Field(nameof(RegistrationForm.LastName))
                    .Field(nameof(RegistrationForm.Email))
                    .Field(nameof(RegistrationForm.ModelNumber), validate: async (state, value) =>
                    {
                       // Validate Model number here
                        ValidateResult validateResult = new ValidateResult()
                        {
                            /*if modelSuggestion != null && modelsSuggestion.Any()*/
                            IsValid = true, //Set true or false
                            Value = value
                        };

                        return validateResult;
                    })
                    .Field(nameof(RegistrationForm.DateOfPurchase))
                    .Field(nameof(State))
                    .Field(nameof(RegistrationForm.KeepMeUpdatedForProductsAndPromotions))
                    .Confirm("Are the information correct?" +
                             "\n\rFirst Name:{FirstName}" +
                             "\n\rLast Name:{LastName}" +
                             "\n\rEmail:{Email}" +
                             "\n\r{&ModelNumber}:{ModelNumber}" +
                             "\n\r{&DateOfPurchase}:{DateOfPurchase}" +
                             "\n\rState:{State}" +
                             "\n\r{&KeepMeUpdatedForProductsAndPromotions}:{KeepMeUpdatedForProductsAndPromotions}?")
                    .OnCompletion(processOrder)
                    .Build();
        }
    }


The above Registration Form Builder is very simple. It will enable bot to ask one by one each property. Furthermore, the Bot is intelligent enough to ask for user input based on variable types.

How to Call Registration Form Builder in MessageController


 internal static IDialog MakeRootDialog()
        {
            var pimServiceClient = Context.Resolve();
            return Chain.From(() => new FormDialog(new RegistrationForm(), Context.Resolve().BuildForm));
        }

        [ResponseType(typeof(void))]
        public virtual async Task Post([FromBody] Activity activity)
        {
            if (activity != null)
            {
                
                // one of these will have an interface and process it
                switch (activity.GetActivityType())
                {
                    case ActivityTypes.Message:
                        await Conversation.SendAsync(activity, MakeRootDialog);
                        break;
                    case ActivityTypes.ConversationUpdate:
                    case ActivityTypes.ContactRelationUpdate:
                    case ActivityTypes.Typing:
                    case ActivityTypes.DeleteUserData:
                    default:
                        Trace.TraceError($"Unknown activity type ignored: {activity.GetActivityType()}");
                        break;
                }
            }
            var response = Request.CreateResponse(HttpStatusCode.OK);
            return response;
         }


Once you compile the solution and run the Emulator you should see the below flow of conversation.




In the next part we will enable the dependency injection of our service using Autofac.

2 comments:

  1. if user type "quit" ! . what is happen?

    ReplyDelete
  2. Hi Ky Son,

    I tried "quit" and i am receiving below error

    Microsoft.Bot.Builder.FormFlow.FormCanceledException1[ElectroluxRegistrationBot.Forms.RegistrationForm]: Form quit. at Microsoft.Bot.Builder.FormFlow.FormDialog.

    I am looking into this and will update accordingly.
    Let me know if you have already looked into it.

    ReplyDelete