Search code examples
c#botframeworkbotsadaptive-cards

How do I handle Postback from AdaptiveCard in OnTurnAsync-Method


I'm programming a bot that is using adaptive Cards ChoiceSet. Im trying to get the users choice. Now because the result doesnt Show in the Chat, I have to check in the OnTurnAsync-Method, if the Message I get is a postback. How do i do this? This is how I tried -> Null ReferenceException at if (dc.Context.Activity.GetType().GetProperty("ChannelData") != null)

Edit from Botframework Support: Please do not use the code block below. It only works in Emulator. Instead, use:

if (string.IsNullOrWhiteSpace(activity.Text) && activity.Value != null)
{
    activity.Text = JsonConvert.SerializeObject(activity.Value);
}

My OnTurnAsync-Method:

public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
    {
        DialogContext dc = null;

        switch (turnContext.Activity.Type)
        {
            case ActivityTypes.Message:
                if (dc.Context.Activity.GetType().GetProperty("ChannelData") != null)
                {
                    var channelData = JObject.Parse(dc.Context.Activity.ChannelData.ToString());
                    if (channelData.ContainsKey("postback"))
                    {
                        var postbackActivit = dc.Context.Activity;
                        postbackActivit.Text = postbackActivit.Value.ToString();
                        await dc.Context.SendActivityAsync(postbackActivit);
                    }
                }

                await ProcessInputAsync(turnContext, cancellationToken);
                break;


Solution

  • It's because of your line: DialogContext dc = null.

    It should be: var dc = await Dialogs.CreateContextAsync(turnContext);

    Note that Dialogs might need to be replaced with whatever you defined your DialogSet with. There's a few different ways to do it, but here's the upper half of my <myBot>.cs class that I used to test your previous issue:

    public class QuickTestBot_CSharpBot : IBot
        {
            private readonly IStatePropertyAccessor<DialogState> _dialogStateAccessor;
            private readonly ConversationState _conversationState;
            public QuickTestBot_CSharpBot(ConversationState conversationState)
            {
                _conversationState = conversationState ?? throw new ArgumentNullException(nameof(conversationState));
                _dialogStateAccessor = _conversationState.CreateProperty<DialogState>(nameof(DialogState));
    
                Dialogs = new DialogSet(_dialogStateAccessor);
                Dialogs.Add(new QuickDialog());
    
            }
    
            private DialogSet Dialogs { get; set; }
    
            public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
            {
                var activity = turnContext.Activity;
    
                var dc = await Dialogs.CreateContextAsync(turnContext);
    
                if (string.IsNullOrWhiteSpace(activity.Text))
                {
                    activity.Text = JsonConvert.SerializeObject(activity.Value);
                }
        [...]
    
    

    Here's some links to a few good samples that also use Waterfall Dialogs, so you can see how they set up their <bot>.cs class (note that they don't get input from adaptive cards...this is just to help you set up your waterfall dialog and OnTurnAsync):

    1. MultiTurnPromptsBot
    2. CardsBot
    3. BasicBot