Proactive Messages in ASP.NETCore 3.1.1

April 19, 2021

Proactive messaging provides your bot the ability to notify the user with messages that can be written and modified by the developer.


Preface

This post serves as an update to an older post I made for proactive messages. It has come to my attention that my older post does not work for newer versions of .NETCore, thus an update is in order.


Create

Let’s get to it!
In this demo we will be using a basic bot created in Azure using Azure Bot Service. To create one you can visit this post.
Open your Visual Studio project and create a new class named NotifyController.cs. This is the controller that handles the proactive messages. In line 42 you can change the message that is presented to the user by the bot. In line 35 you can find the page that gets loaded when you hit the endpoint.

using System.Collections.Concurrent;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Schema;

namespace Microsoft.BotBuilderSamples.Dialogs
{
    [Route("api/notify")]
    [ApiController]
    public class NotifyController : ControllerBase
    {
        private IBotFrameworkHttpAdapter _externAdapter;
        private ConcurrentDictionary<string, ConversationReference> _userReference;
        public NotifyController(IBotFrameworkHttpAdapter adapter, ConcurrentDictionary<string, ConversationReference> conReferences)
        {
            _externAdapter = adapter;
            _userReference = conReferences;
        }

        public async Task<IActionResult> Get()
        {
            foreach (var conversationReference in _userReference.Values)
            {
                await ((BotAdapter)_externAdapter).ContinueConversationAsync(string.Empty, conversationReference,
                    ExternalCallback, default(CancellationToken));
            }

            var result = new ContentResult();
            result.StatusCode = (int)HttpStatusCode.OK;
            result.ContentType = "text/html";
            result.Content = "<html>Proactive messages have been sent.</html>";

            return result;
        }

        private async Task ExternalCallback(ITurnContext turnContext, CancellationToken cancellationToken)
        {
            await turnContext.SendActivityAsync(MessageFactory.Text("This is a proactive message!"), cancellationToken);
        }
    }
}


Implement

Open the Startup.cs class and add the following using statements.

      using System.Collections.Concurrent;
      using Microsoft.Bot.Schema;

In the ConfigureServices function add the following service.

      services.AddSingleton<ConcurrentDictionary<string, ConversationReference>>();

Open the DialogBot.cs and add the following using statement.

      using System.Collections.Concurrent;

Add the ConcurrentDictionary

      private ConcurrentDictionary<string, ConversationReference> _userConversationReferences;

Change the constructor by adding the ConcurrentDictionary in line 1 and line 7.

public DialogBot(ConversationState conversationState, UserState userState, T dialog, ILogger<DialogBot<T>> logger, ConcurrentDictionary<string, ConversationReference> userConversationReferences)
{
    ConversationState = conversationState;
    UserState = userState;
    Dialog = dialog;
    Logger = logger;
    _userConversationReferences = userConversationReferences;
}

Add this function at the end of the class.

protected override Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
    if (turnContext.Activity is Activity activity)
    {
        var conReference = activity.GetConversationReference();

        _userConversationReferences.AddOrUpdate(conReference.User.Id, conReference,
            (key, newValue) => conReference);
    }

    return base.OnConversationUpdateActivityAsync(turnContext, cancellationToken);
}

Lastly, open the DialogAndWelcomeBot.cs class and add the following using statement.

      using System.Collections.Concurrent;

And add the ConcurrentDictionary constructor method in lines 1-2.

public DialogAndWelcomeBot(ConversationState conversationState, UserState userState, T dialog, ILogger<DialogBot<T>> logger, ConcurrentDictionary<string, ConversationReference> userConversationReferences)
    : base(conversationState, userState, dialog, logger, userConversationReferences)
{
}


Test

To test, simply run your bot and load up the emulator like normally, you should get the following messages.


Now to trigger the proactive message click the following link: http://localhost:3978/api/notify
You should see this page in your browser informing you that the Proactive messages have been sent.


Now you should see the new message in your emulator!


This is how you implement proactive messages to your bot to notify the user in ASP.NETCore 3.1.1!

About Me

Hi, my name is Demetris Bakas and I am a software engineer that loves to write code and be creative. I always find new technologies intriguing and I like to work with other people and be a part of a team. My goal is to develop software that people will find useful and will aid them in their everyday lives.
For any questions feel free to contact me at social media using the links below.