Create Bot for Microsoft Graph with DevOps 18: DirectLine

In this article, I explain DirectLine which you can hook your service to bot via REST endpoint.

DirectLine

As you know already, bot connector supports multiple channels such as Skype, Facebook, Email, etc. However if you want to connect other channels like WeChat, LINE or even your own application, you can use DirectLine. Does O365Bot uses it? Yes it is in function test project.

Features

  • Authentication against REST endpoint
  • Start and end conversation
  • Send and receive messages (activities)
  • Support HTTP POST/GET or WebSocket

Limitations

You cannot receive proactive message from the bot without WebSockets. The typical workflow is:

  1. Start a conversation and send message.
  2. Bot returns completed message only when all the code are executed. Therefore you cannot get the response real-time.
  3. Request for queued activities, which includes your own activity sent to the bot.

Watermark

To avoid keep receiving old activities, you can specify “watermark” like paging.

Function Test

I use DirectLine in Function Test project in DirectLineHelper.cs.

Try WebSocket

As normal POST/GET methods are used inside O365bot, let’s try WebSocket in this article.

1. Add console application to O365 solution and name it “O365Bot.StreamClient“.

2. Add DirectLIne and WebSocketSharp from NuGet. Also add System.Configuration assembly.

image

image

3. Add DirectLine and UserId to app.config file.

image

4. Replace the code in Program.cs

using Microsoft.Bot.Connector.DirectLine;
using Newtonsoft.Json;
using System;
using System.Configuration;
using System.Linq;
using System.Threading.Tasks;
using WebSocketSharp;

namespace O365Bot.StreamClient
{
    class Program
    {
        static string userId = ConfigurationManager.AppSettings["UserId"];
        static void Main(string[] args)
        {
            Run().Wait();
        }

        private static async Task Run()
        {

            var client = new DirectLineClient(ConfigurationManager.AppSettings["DirectLineSecret"]);
            // Create a conversation
            var conversation = await client.Conversations.StartConversationAsync();
            using (var webSocketClient = new WebSocket(conversation.StreamUrl))
            {
                // Callback when message is received.
                webSocketClient.OnMessage += WebSocketClient_OnMessage;
                webSocketClient.Connect();

                while (true)
                {
                    var input = Console.ReadLine();
                    if (input == ConsoleKey.Enter.ToString())
                        break;

                    Activity activity = new Activity()
                    {
                        From = new ChannelAccount(userId, userId),
                        Text = input,
                        Locale = "en-US",
                        Type = ActivityTypes.Message
                    };

                    await client.Conversations.PostActivityAsync(conversation.ConversationId, activity);
                }
            }
        }

        private static void WebSocketClient_OnMessage(object sender, MessageEventArgs e)
        {
            if (string.IsNullOrWhiteSpace(e.Data))
                return;
            var activitySet = JsonConvert.DeserializeObject<ActivitySet>(e.Data);

            foreach (var activity in activitySet.Activities.Where(x => x.From.Id != userId))
            {
                // Process message
                Console.WriteLine(activity.Text);
            }
        }
    }
}

Run the app

Just run the app by pressing F5 to see how it works. It should work similar to what you have already, but when bot returns message, it received real-time.

Summery

DirectLine is powerful endpoint which you can enable bot anywhere, everywhere. There is another sample using DirectLine which connect LINE and BotFramework here.

Ken