botframeworkproactive

Bot Framework Proactive Message Passing Id Into Conversation State


I have a SMS / Twilio Channel that I'm using to send out a Proactive message to the user. To send the Proactive message I'm calling a API method passing in MySpecialId which is used later in the conversation.

I want to save this MySpecialId into the conversation but at the point I have the MySpecialId the conversation doesn't exist yet, and I don't have a turnContext, so I can't really save it yet.

Is there a way to pass this Id from my API method into the BotCallback? I created a quick example. (Here is the original example I'm using https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/16.proactive-messages)

Thanks

        [HttpGet("{number}")]
        public async Task<IActionResult> Get(string MySpecialId)
        {
            //For Twillio Channel
            MicrosoftAppCredentials.TrustServiceUrl("https://sms.botframework.com/");

            var NewConversation = new ConversationReference
            {
                User = new ChannelAccount { Id = $"+1{PHONENUMBERTOTEXTHERE}" },
                Bot = new ChannelAccount { Id = "+1MYPHONENUMBERHERE" },
                Conversation = new ConversationAccount { Id = $"+1{PHONENUMBERTOTEXTHERE}" },
                ChannelId = "sms",
                ServiceUrl = "https://sms.botframework.com/"
            };

        BotAdapter ba = (BotAdapter)_HttpAdapter;
            await ((BotAdapter)_HttpAdapter).ContinueConversationAsync(_AppId, NewConversation, BotCallback, default(CancellationToken));

            return new ContentResult()
            {
                Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
                ContentType = "text/html",
                StatusCode = (int)HttpStatusCode.OK,
            };
        }

      private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
        {
            try
            {
                var MyConversationState = _ConversationState.CreateProperty<MyConversationData>(nameof(MyConversationData));
                var ConversationState = await MyConversationState.GetAsync(turnContext, () => new MyConversationData(), cancellationToken);

                //********************************************************************************************************************
                ConversationState.MySpecialId = //HOW DO I GET MySpecialId FROM THE GET METHOD ABOVE HERE?
                //********************************************************************************************************************

                await _ConversationState.SaveChangesAsync((turnContext, false, cancellationToken);
                await turnContext.SendActivityAsync("Starting proactive message bot call back");                    
            }
            catch (Exception ex)
            {
                this._Logger.LogError(ex.Message);
            }
        }

Solution

  • I don't believe that you can. Normally, you would do something like this by passing values through Activity.ChannelData, but ChannelData doesn't exist on ConversationReference.


    Per comments below, @Ryan pointed out that you can pass data on ConversationAccount.Properties. Note, however, this is currently only available in the C# SDK. I've opened an issue to bring this into the Node SDK, but ETA is unknown at this point.


    Instead, I'd suggest using a something more native to C#, like:

    1. Create a ConcurrentDictionary
    private ConcurrentDictionary<string, string> _idMap;
    
    1. Map MySpecialId to Conversation.Id (in your Get function)
    _idMap.AddOrUpdate(conversationReference.Conversation.Id, MySpecialId, (key, newValue) => MySpecialId);
    
    1. Access the MySpecialId from the Activity.Conversation.Id (in BotCallback)
    var ConversationState = await MyConversationState.GetAsync(turnContext, () => new MyConversationData(), cancellationToken);
    ConversationState.MySpecialId = _idMap.GetValueOrDefault(turnContext.Activity.Conversation.Id);
    
    1. Save ConversationState
    await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
    

    There's other ways you could do this and some validation checks you'll need to add, but this should get you started.