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:
- Start a conversation and send message.
- Bot returns completed message only when all the code are executed. Therefore you cannot get the response real-time.
- 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.
3. Add DirectLine and UserId to app.config file.
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