Calling The Microsoft Bot Framework Using The Direct Line API (MS Bot Framework V4 Preview Edition)

Jul 29

Written by:
7/29/2018 10:01 AM  RssIcon

image

The Microsoft Bot Framework V4 allows you to create intelligent bots that interact naturally wherever your users are (text/SMS to Skype, Slack, Office 365 mail and other popular services). In preview now, the Bot Builder V4 Preview SDK offers new features and is extensible with a pluggable middleware model.

image

You may need to call your Microsoft Bot Framework Bot directly from a custom application, a service, or a website. The Microsoft Bot Connector Direct Line REST API allows you to do this. In addition, it allows you to authenticate a user in your application, and securely communicate with the Bot as that user.

The Direct Line API exposes a REST API that allows you to communicate with a single Bot that has been registered with the Microsoft Bot Connector Service. This API is intended for developers who want to communicate with their Bot from their own client applications, such as mobile apps, a service, or even an Amazon Alexa.

Tutorial Series

Other articles in this series:

Requirements

Sample

We will start with the code from: Creating a Hello World! Bot (MS Bot Framework V4 Preview Edition) (it is on the Downloads page of this site).

We will enable it to work with the  Microsoft Bot Connector Direct Line REST API.

Configuring The Direct Line Connector

We want to configure the Direct Line connector for our Bot.

The procedure for working with the Direct Line API is:

  1. Create a Direct Line Channel in the Bot Channels Registration for the Bot
  2. Use the secret key obtained from Direct Line Channel registration to make REST based calls to communicate with the Bot (in our example, we will use the Microsoft.Bot.Connector.DirectLine Nuget package to help us make the calls).

image

Go to https://portal.azure.com and log in.

Locate the Bot Channels Registration created in following the tutorial: Creating a Hello World! Bot (MS Bot Framework V4 Preview Edition).

Click on it.

image

Click on Channels then the Direct Line channel icon.

image

When the Configure Direct Line page appears, click the show link to display the secret key.

Copy the key and save it, you will need it later.

Ensure 3.0 is selected and click the Done button.

image

Direct Line will show in the list of the configured channels for the Bot.

image

Click on the Settings tab.

Copy the Bot handle (this is your BotID).

Copy the name and save it, you will need it later.

 

Create The Project

Open Visual Studio.

image

From the toolbar in Visual Studio, select File, then New, then Project.

image

Select Web, then ASP.NET Web Application (.Net Framework).

Enter DirectLineBot for the Name.

Select the Create directory for solution box.

Press OK.

image

When the application configuration box appears, select the MVC template.

Ensure that Individual User Accounts is selected for Authentication (if not, click the Change Authentication button and change it).

Press OK.

image

The application will be created.

image

We need to add the Microsoft.Bot.Connector.DirectLine Nuget package that will allow us to easily communicate with the DirectLine API.

In the Solution Explorer, right-click on the DirectLineBot project node (not the Solution node), and select Manage Nuget Packages.

image

When the Nuget Packages configuration window appears…

Click the Browse button.

Enter Microsoft.Bot.Connector.DirectLine in the search box to conduct the search.

When the Microsoft.Bot.Connector.DirectLine package shows up, click on it (so that it’s properties appears in the window on the right).

Click the Install button to install the package.

image

Click Ok when the Preview window shows.

image

Click the I Accept button when the License Acceptance window appears.

image

The Microsoft.Bot.Connector.DirectLine assembly will be installed.

image

Hit F5 to debug and run the application.

The application will open in the web browser.

image

You will see that the default web application, created by the MVC template, contains an About and a Contact page. We can stop the application (by closing the web browser), and remove the code for these pages because we don’t need them.

If you don’t know how to do that, you can leave them in the application (note: You can download the completed application from the downloads page on this site).

What we do care about is the ability to click the Register button to create a new account.

We can also click the Log in button to log in using a registered account.

 

Complete The Web Application

image

We will update the home page to show the chat box and the Bot response only if the user has created an account and logged in.

Open the Index.cshtml file (in the Views/Home folder), and replace all the code with the following code:

 
@model DirectLine.Controllers.Chat
<h2>Direct Line Bot Example</h2>
@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
    <p>
        Hello: @((User.Identity.IsAuthenticated == true)
         ? User.Identity.Name
         : "[Unknown]")
    </p>
    @Html.TextBoxFor(m => m.ChatMessage,
    new { style = "width:600px" })
    <input type="submit" value="Send" />
}
<br />
<p>@Html.Raw(Model.ChatResponse)</p>
 

image

Open the HomeController.cs file (in the Controllers folder), and replace all the code with the following code:

 
    using Microsoft.Bot.Connector.DirectLine;
    using Newtonsoft.Json;
    using System;
    using System.Linq;
    using System.Threading.Tasks;
    using System.Web.Mvc;
    namespace DirectLine.Controllers
    {
        #region public class Chat
        public class Chat
        {
            public string ChatMessage { get; set; }
            public string ChatResponse { get; set; }
            public string watermark { get; set; }
        }
        #endregion
        public class HomeController : Controller
        {
            private static string DiretlineUrl
                = @"https://directline.botframework.com";
            private static string directLineSecret =
                "** INSERT YOUR SECRET CODE HERE **";
            private static string botId =
                "** INSERT YOUR BOTID HERE **";
            #region public async Task<ActionResult> Index()
            public async Task<ActionResult> Index()
            {
                // Create an Instance of the Chat object
                Chat objChat = new Chat();
                // Only call Bot if logged in
                if (User.Identity.IsAuthenticated)
                {
                    // Pass the message to the Bot 
                    // and get the response
                    objChat = await TalkToTheBot("Hello");
                }
                else
                {
                    objChat.ChatResponse = "Must be logged in";
                }
                // Return response
                return View(objChat);
            }
            #endregion
        }
    }
 

At this point the code is not complete, however, it sets up the basic framework.

Remember to replace, ** INSERT YOUR SECRET CODE HERE ** and ** INSERT YOUR BOTID HERE ** with the values from you own published Bot.

When a logged in user loads the page, or submits text to the Bot, the TalkToTheBot method is called.

To implement it, add the following method to the HomeController class:

 

        #region private async Task<Chat> TalkToTheBot(string paramMessage)
        private async Task<Chat> TalkToTheBot(string paramMessage)
        {
            // Connect to the DirectLine service
            DirectLineClient client = new DirectLineClient(directLineSecret);
            // Try to get the existing Conversation
            Conversation conversation =
                System.Web.HttpContext.Current.Session["conversation"] as Conversation;
            // Try to get an existing watermark 
            // the watermark marks the last message we received
            string watermark =
                System.Web.HttpContext.Current.Session["watermark"] as string;
            if (conversation == null)
            {
                // There is no existing conversation
                // start a new one
                conversation = await client.Conversations.StartConversationAsync();
            }
            // Use the text passed to the method (by the user)
            // to create a new message
            Activity userMessage = new Activity
            {
                From = new ChannelAccount(User.Identity.Name),
                Text = paramMessage,
                Type = ActivityTypes.Message
            };
            // Post the message to the Bot
            await client.Conversations.PostActivityAsync(conversation.ConversationId, userMessage);
            // Get the response as a Chat object
            Chat objChat =
                await ReadBotMessagesAsync(client, conversation.ConversationId, watermark);
            // Save values
            System.Web.HttpContext.Current.Session["conversation"] = conversation;
            System.Web.HttpContext.Current.Session["watermark"] = objChat.watermark;
            // Return the response as a Chat object
            return objChat;
        }
        #endregion

 

The TalkToTheBot method calls the ReadBotMessagesAsync method to read the response from the Bot.

To implement it, add the following method to the HomeController class:

        
        #region private async Task<Chat> ReadBotMessagesAsync(DirectLineClient client, string conversationId, string watermark)
        private async Task<Chat> ReadBotMessagesAsync(
            DirectLineClient client, string conversationId, string watermark)
        {
            // Create an Instance of the Chat object
            Chat objChat = new Chat();
            // We want to keep waiting until a message is received
            bool messageReceived = false;
            while (!messageReceived)
            {
                // Retrieve the activity set from the bot.
                var activitySet = await client.Conversations.GetActivitiesAsync(conversationId, watermark);
                // Set the watermark to the message received
                watermark = activitySet?.Watermark;
                // Extract the activies sent from our bot.
                var activities = (from Activity in activitySet.Activities
                                  where Activity.From.Id == botId
                                  select Activity).ToList();
                // Analyze each activity in the activity set.
                foreach (Activity activity in activities)
                {
                    // Set the text response
                    // to the message text
                    objChat.ChatResponse
                        += " "
                        + activity.Text.Replace("\n\n", "<br />");
                    // Are there any attachments?
                    if (activity.Attachments != null)
                    {
                        // Extract each attachment from the activity.
                        foreach (Attachment attachment in activity.Attachments)
                        {
                            switch (attachment.ContentType)
                            {
                                case "image/png":
                                    // Set the text response as an HTML link
                                    // to the image
                                    objChat.ChatResponse
                                        += " "
                                        + attachment.ContentUrl;
                                    break;
                            }
                        }
                    }
                }
                // Mark messageReceived so we can break 
                // out of the loop
                messageReceived = true;
            }
            // Set watermark on the Chat object that will be 
            // returned
            objChat.watermark = watermark;
            // Return a response as a Chat object
            return objChat;
        }
        #endregion

 

We also need the following method to call the code when the user enters text and clicks the Submit button:

 

        #region public async Task<ActionResult> Index(Chat model)
        [HttpPost]
        public async Task<ActionResult> Index(Chat model)
        {
            // Create an Instance of the Chat object
            Chat objChat = new Chat();
            // Only call Bot if logged in
            if (User.Identity.IsAuthenticated)
            {
                // Pass the message to the Bot 
                // and get the response
                objChat = await TalkToTheBot(model.ChatMessage);
            }
            else
            {
                objChat.ChatResponse = "Must be logged in";
            }
            // Return response
            return View(objChat);
        }
        #endregion

 

Run The Project

image

Hit F5 to run the application.

image

The application will open in the web browser. Initially we are not logged in so we will be unable to communicate with the Bot.

image

Click the Register button to create an account.

image

Fill in the required information and click the Register button.

image

After you have created an account, you can click the Log in button to log in (if you are not already logged in).

image

You will know you are logged in when you see your email address in the menu bar and on the Homepage.

You can now communicate with the Bot and run the same code that was created and deployed in the article: Creating a Hello World! Bot (MS Bot Framework V4 Preview Edition):

image

image

image

This demonstrates that we are able to authenticate users using our own custom code, and have them communicate with the Bot securely, when using the Direct Line API.

 

Links

How to create a Direct Line bot and client

Connect a bot to Direct Line

alexa-bridge

Azure Bot Service Documentation for the v4 SDK

Conversational AI: Best Practices for Building Bots

Find Your Azure Bot’s AppID and AppSecret

Download

You can download the code from the Download page