Create a bot using the Proactive template

Typically, each message that a bot sends to the user directly relates to the user's prior input. In some cases though, a bot may need to send the user information that is not directly related to the user's most recent message. These types of messages are called proactive messages. Proactive messages can be useful in a variety of scenarios. For example, if a bot sets a timer or reminder, it may need to notify the user when the time arrives. Or, if a bot receives a notification about an external event, it may need to communicate that information to the user.

To create a bot that can send proactive messages to the user, choose the Proactive template when creating the bot using Azure Bot Service. This article describes the Azure resources that are created when you create a bot using the Proactive template and provides a walkthrough of the code that is automatically generated by the template.

Azure resources

When you create a bot by using the Proactive template, several Azure resources are automatically created and added to your resource group. By default, these Azure resources are already configured to enable a very simple proactive messaging scenario.

Resource Description
Azure Storage Used to create the queue.
Azure Function App A queueTrigger Azure Function that is triggered whenever there is a message in the queue. It communicates to the Azure Bot Service by using Direct Line. This function uses bot binding to send the message as part of the trigger’s payload. Our example function forwards the user’s message as-is from the queue.
Azure Bot Service Your bot. Contains the logic that receives the message from user, adds the message to the Azure queue, receives triggers from Azure Function, and sends back the message it received via trigger's payload.

Process overview

This diagram shows how triggered events work when you create a bot using the Proactive template.

Overview of example Proactive Bot

The process begins when the user sends a message to your bot via Bot Framework servers (step 1). The Code walkthrough section of this article describes the remaining steps of the process.

Code walkthrough

Receive a message from the user and add it to an Azure Storage queue

When the bot receives a message from the user (step 2), it adds the message to the Azure Storage queue (step 3), and notifies the user (via the Bot Framework servers) that the message has been queued (step 4). The message is encapsulated within an object that contains information that will eventually be needed to send the proactive message to the user on the correct channel.

This code snippet uses C# to receive a message from the user, add the message to the Azure Storage queue, and notify the user that the message has been queued. The RelatesTo property of the queue message is set to a ConversationReference object, which contains the information that is needed to respond to the user on the correct channel.

public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
    var message = await argument;

    // Create a queue Message
    var queueMessage = new Message
    {
        RelatesTo = context.Activity.ToConversationReference(),
        Text = message.Text
    };

    // Write the queue Message to the queue
    // AddMessageToQueue() is a utility method you can find in the template
    await AddMessageToQueue(JsonConvert.SerializeObject(queueMessage));
    await context.PostAsync($"{this.count++}: You said {queueMessage.Text}. Message added to the queue.");
    context.Wait(MessageReceivedAsync);
}

This code snippet uses Node.js to receive a message from the user, add the message to the Azure Storage queue, and notify the user that the message has been queued. The session.message.address object contains the information that is needed to respond to the user on the correct channel.

bot.dialog('/', function (session) {
    var queuedMessage = { address: session.message.address, text: session.message.text };
    session.sendTyping();
    var queueSvc = azure.createQueueService(process.env.AzureWebJobsStorage);
    queueSvc.createQueueIfNotExists('bot-queue', function(err, result, response){
        if(!err){
            var queueMessageBuffer = new Buffer(JSON.stringify(queuedMessage)).toString('base64');
            queueSvc.createMessage('bot-queue', queueMessageBuffer, function(err, result, response){
                if(!err){
                    session.send('Your message (\'' + session.message.text + '\') has been added to a queue, and it will be sent back to you via a Function');
                } else {
                    session.send('There was an error inserting your message into queue');
                }
            });
        } else {
            session.send('There was an error creating your queue');
        }
    });
});

Trigger an Azure Function and send the message to the bot

After the message is added to the queue, the function is automatically triggered (step 5). The message is then removed from the queue and sent back to the bot (step 6). The function's configuration file (functions.json) contains an input binding of type queueTrigger and an output binding of type bot.

{
  "bindings": [
    {
      "name": "myQueueItem",
      "type": "queueTrigger",
      "direction": "in",
      "queueName": "bot-queue",
      "connection": ""
    },
    {
      "type": "bot",
      "name": "$return",
      "direction": "out",
      "botId": "yourbot"
    },
    {
      "type": "http",
      "name": "res",
      "direction": "out"
    }
  ]
}

This code snippet shows the Function code in C#.

using System;
using System.Net;
using System.Net.Http;
using Microsoft.Azure.WebJobs.Host;

public class BotMessage
{
    public string Source { get; set; } 
    public string Message { get; set; }
}

public static HttpResponseMessage Run(string myQueueItem, out BotMessage message, TraceWriter log)
{
    message = new BotMessage
    { 
        Source = "Azure Functions (C#)!", 
        Message = myQueueItem
    };

    return new HttpResponseMessage(HttpStatusCode.OK); 
}

This code snippet shows the Function code in Node.js.

module.exports = function (context, myQueueItem) {
    context.log('Sending Bot message', myQueueItem);

    var message = {
        'text': myQueueItem.text,
        'address': myQueueItem.address
    };

    context.done(null, message);
}

Receive the message from the Azure Function and send proactive message

Finally, the bot receives the message from the trigger function (step 7) and sends a proactive message to the user (step 8).

This code snippet uses C# to receive the message from the Azure Function and send a message to the user.

switch (activity.GetActivityType())
{
    case ActivityTypes.Event:
        // handle proactive Message from function
        IEventActivity triggerEvent = activity;
        var message = JsonConvert.DeserializeObject<Message>(((JObject) triggerEvent.Value).GetValue("Message").ToString());
        var messageactivity = (Activity)message.RelatesTo.GetPostToBotMessage();
        
        client = new ConnectorClient(new Uri(messageactivity.ServiceUrl));
        var triggerReply = messageactivity.CreateReply();
        triggerReply.Text = $"This is coming back from the trigger! {message.Text}";
        await client.Conversations.ReplyToActivityAsync(triggerReply);
        break;
    default:
        break;
}

This code snippet uses Node.js to receive the message from the Azure Function and send a message to the user.

bot.on('trigger', function (message) {
    // handle message from trigger function
    var queuedMessage = message.value;
    var reply = new builder.Message()
        .address(queuedMessage.address)
        .text('This is coming from the trigger: ' + queuedMessage.text);
    bot.send(reply);
});

Extend default functionality

The Proactive template provides a good foundation that you can build upon and customize to enable proactive messaging scenarios for your bot. To learn more about sending proactive messages, see Send proactive messages with .NET or Send proactive messages with Node.js.

Additional resources