How to use Bot Service in Xamarin.Forms project (DirectLine version)

Background

This article is a further topic of last WebView version. I mentioned in that article, the pro for WebView version is easy to implement. However, using that approach, we will totally depend on the bot development, there is no much things to do in Xamarin development.

Also, Google has published lots of restricts to use WebView.

In this article, I will introduce another approach which is also recommended by myself. We are going to use Direct Line Service to communicate with our Bot using Xamarin app.

Pros

We are going to use the MVVM structure to implement this, which is also the most popular structure for Xamarin development.

By using this approach, all the things will be handled in Xamarin actually such as the UI of the Bot chat.

Cons

You need to know deeper on Xamarin development also the Bot development. You need to know how to use Direct Line service to send message to Bot, MVVM structure, etc.

Technical Skill introduction

First you need to get familiar about Key concepts in Direct Line API 3.0, then you will know what is Direct Line and how it can be used.

But in this article we will not use the approaches in the above document, because if you look into the document, you will see it introduces the Direct Line API as the Web API. For example, if you want to start a new conversation, you will have to use the API as below screenshot:

In that case, whenever we need to do anything with Direct Line service, we will have to create a HttpClient to send a web request. That is really pain in the ass.

Therefore, we are looking for the Direct Line SDK which is a NuGet package.

Direct Line NuGet package

To use the Direct Line SDK, we will have add 2 NuGet packages as dependencies:

The first one is quite straightforward and makes sense. It just wrapped the Web API calling to C# class and methods.

The second library should be some dependency library for MS client application to call the Rest API.

Implementation

Azure

First we need to create a Direct Line Channel for the bot on Azure portal. Just log on to Azure portal -> Bot Service -> Channels -> Enable Direct Line Channel.

We still get the Key from the Edit page of the Channel.

Now we go back to Xamarin.

Xamarin

First we need to implement a class, named BotConnection.cs which defines the connection to Bot, sending messages, receiving messsages, etc. These methods are all the basic operations for communication with Bot.

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class BotConnection
{
// Fields
public string botId "Your_Bot_Id_here";
public string directLineSecret = "Your_Bot_Secret_here";
public DirectLineClient directLineClient;
public Conversation MainConversation;
public ChannelAccount Account;

public BotConnection(string accountName)
{
// Obtain a token using Direct Line Secret
var tokenResponse = new DirectLineClient(directLineSecret).Tokens.GenerateTokenForNewConversation();

// Use token to create conversation
directLineClient = new DirectLineClient(tokenResponse.Token);
MainConversation = directLineClient.Conversations.StartConversation();
Account = new ChannelAccount { Id = accountName, Name = accountName };
}
}

Let me introduce the fields first.

  • botId: used to determine which bot is communicating with us. This one will be used later when we try to receive messages from bot. Note that we will only listen the messages from the Bot that we should be communicating with.
  • directLineSecret: the secrect key we got from the Direct Line channel.
  • DirectLineClient: used to instantiate the Direct Line. We use this Client to create conversations, sending messages, receiving messages, etc. All the operations that related to communication with Bot is done by this class.
  • Conversation: the conversation instance between Xamarin app and Bot. In this demo, we only used the MainConversation. I suppose there should be some scenarios that we need to create multiple conversations in one Bot chat.
  • ChannelAccount: identity for the Xamarin app, to identify which Account is communicating with Bot.

We still use the same approach which is to use the access token to create conversation. Notice that we still can directly use the subscription key to start the conversation.

Next we need to implement a SendMessage method. This method is used to send messages from end users to Bot. All the messages in Bot, they actually are Activity. Activity has a type property, which is a ActivityType enum.

For example, when we send a normal string message, we are using ActivityType.Message as the value for Activity’s Type.

Code:

1
2
3
4
5
6
7
8
9
10
public void SendMessage(string message)
{
Activity activity = new Activity
{
From = Account,
Text = message,
Type = ActivityType.Message
};
directLineClient.Conversations.PostActivity(MainConversation.ConversationId, activity);
}

Since we are trying to use MVVM to implement this demo, we need to design a Model. This model is for the “messages” that will be displayed in the UI.

In this demo, we only implement the Bot which communicates with string only. So the main fields for this Message model is Text and Sender. We will also add some properties which are TextAlighment to set the message’s position. (Bot’s message in the left, and users’ message in the right).

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Message
{
public string Text {get;set;}
public string Sender {get;set;}

public TextAlignment LblMessageHorizontalTextAlignment {get;set;}
public TextAlignment LblSenderHorizontalTextAlignment {get;set;}

public Message(string text, string sender)
{
Text = text;
Sender = sender;
if (Sender.ToUpper() == "ME")
{
LblMessageHorizontalTextAlignment = TextAlignment.End;
LblSenderHorizontalTextAlignment = TextAlignment.End;
}
else
{
LblMessageHorizontalTextAlignment = TextAlignment.Start;
LblSenderHorizontalTextAlignment = TextAlignment.Start;
}
}
}

Notice that I hard coded the sender as “ME”. This is due to we only has one user for now, I will figure out what exactly does the BotId, BotName, UserId and UserName should be used in a more common senario.

Last but the most important implementation is the GetMessageAsync method. This method is used to listen from the Bot.

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public async Task GetMessageAsync(ObservableCollection<Message> collection)
{
string watermark = null;
while (true)
{
Debug.WriteLine("Reading message every 3 seconds");

var activitySet = await directLineClient.Conversations.GetActivitiesAsync(MainConversation.ConversationId, watermark);
watermark = activitySet?.Watermark;

foreach (var activity in activitySet.Activities)
{
if (activity.From.Id == botId)
{
collection.Add(new Message(activity.Text, activity.From.Name));
}
}

await Task.Delay(3000);
}
}

Comments:

First notice the parameter’s type is ObservableCollection, we used this because we need to use data binding to automatically update the UI when new messages sent or come.

The await Task.Delay(3000) is to ask the thread to wait for 3 seconds, so actually we are fetching whether there is any message sent by Bot every 3 seconds.

The most important concept here is the Watermark. It marks the last Activity that our client received. With this, every 3 seconds we will only get the latest message that Bot has sent to us. And each time the Watermark will be updated.

Last we are using a standard data binding model to bind the ListView to a ObservableCollection<Message>.

Code demo download link: https://allenxamlistfunctionapp.blob.core.windows.net/allensharing/XamBotDirectLine.zip

Run PowerShell command using .NET SDK How to use Bot Service in Xamarin.Forms project (WebView version)
You need to set install_url to use ShareThis. Please set it in _config.yml.

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×