How can I use the data from an adaptive Card? - c#

I have a chatbot that sends an adaptive card asking a question that looks like this.
Adaptive Card
When an option is pressed, I want to be able to use the data from this card inside of my code.
The JSON file for my card is this:
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.0",
"speak": "Somone is trying to take your session.",
"body": [
{
"type": "TextBlock",
"text": "Someone is taking your session!"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Allow",
"data": {
"Value": "allow"
}
},
{
"type": "Action.Submit",
"title": "Deny",
"data": {
"Value": "deny"
}
}
]
}
I know the bot is receiving something from the card as the event OnMessageActivityAsync is being raised. When I use this bot in the bot framework emulator, it shows here that it IS returning a value.
JSON Response
How can I use this data in my program for a task such as deciding whether the session can be taken in C#?

I solved It by using
var val = turnContext.Activity.Value;
string value = Convert.ToString(val);
return value;
I was using strings and because of the conversion issue I could not find how to access this. By switching it to var solved the issue.

Related

Bot framework-Adaptive card-Unable to get data

I'm new to bot framework and learning. Here I'm looking for a solution I'm facing in Adaptive card that I using for my chatbot. I learn that we can design that adaptive card as per our need using adaptivecards.io/designer where we get the card as json code.
so here is my json code for adaptive card
{
"type": "AdaptiveCard",
"$schema":
"http://adaptivecards.io/schemas/adaptivecard.json",
"version": "1.2",
"msTeams": {
"width": "full"
},
"body": [
{
"type": "TextBlock",
"text": "Adaptive Card Example",
"wrap": true,
"size": "large",
"weight": "bolder",
"id": "title"
},
{
"type": "Input.Text",
"placeholder": "Provide your thoughts",
"separator": true,
"isMultiline": true,
"id": "thoughts"
},
{
"type": "ActionSet",
"separator": true,
"actions": [
{
"type": "Action.Submit",
"title": "Submit",
"style": "positive",
"id": "submit"
}
]
}
]
}
so when I run my bot and see the output in emulator, I can see the adaptive card
adaptive card
when i give the input and click the submit button it showing the error as System.NullReferenceException Object reference not set to an instance of an object.
Please explain in detail to resolve this
I used the same Adaptive card & worked fine
Read value from the adaptive card use the value property ${turn.activity.value}

Mentioning a user in Input.Text field of Adaptive card (C#)

I want to mention a user in Input.Text field of Adaptive Card. Whenever we type "#" in Input.Text, I want a list of all the members of channel to appear like in a normal mention. Is this possible?
Currently the mention feature is not working.
Code of my Adaptive Card -
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"type": "AdaptiveCard",
"version": "1.2",
"speak": "Your meeting about \"Adaptive Card design session\" is starting at ${formatDateTime(start.dateTime, 'HH:mm')}pmDo you want to snooze or do you want to send a late notification to the attendees?",
"body": [
{
"type": "Container",
"items": [
{
"type": "Input.Text",
"id": "comment",
"placeholder": "Please Enter Your Comment"
}
]
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Comment",
"data": {
"x": "comment"
}
}
]
}
The card looks like this:
Thank you for the help.
This is not possible in Teams. To make a feature request, please contact Teams support directly. You can do this through the Teams app or by posting an issue in the Teams docs repo: https://github.com/MicrosoftDocs/msteams-docs/issues

How do you populate Adaptive Card input values on the renderer side after a selection is made in a choice set?

I am using adaptive card templating in bot framework. When user selects a particular value from a dropdown, based on the selection, few input fields on the input form card should be auto populated. How to achieve this?
Based on the dropdown, if user chooses 'myself', his email id should be auto populated in his/her email address textbox(email address I can get from user profile stored in user state).
The adaptive card I am using is as below:
{
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.2",
"body": [
{
"type": "TextBlock",
"text": "Please enter the email Id, on behalf of whom you want to raise the request.",
"wrap": true
},
{
"type": "Input.ChoiceSet",
"id":"dropdown",
"choices": [
{
"title": "Myself",
"value": "Myself"
},
{
"title": "Other",
"value": "Other"
}
],
"placeholder": "Raise request for"
},
{
"type": "Input.Text",
"id": "email",
"placeholder": "Enter email address here",
"validation": {
"necessity": "Required",
"errorMessage": "Email address is required"
}
},
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Submit",
"title": "Submit",
"data": "Submit"
}
]
},
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Submit",
"title": "Cancel",
"data": {
"id": "stepCancel"
}
}
]
}
]
}
I used actions instead of actionset. The card looks something like this:
{
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.2",
"body": [
{
"type": "TextBlock",
"text": "Please enter the email Id, on behalf of whom you want to raise the request.",
"wrap": true
},
{
"type": "Input.ChoiceSet",
"id": "dropdown",
"choices": [
{
"title": "Myself",
"value": "Myself"
},
{
"title": "Other",
"value": "Other"
}
],
"placeholder": "Raise request for"
},
{
"type": "Input.Text",
"id": "email",
"placeholder": "Enter email address here",
"validation": {
"necessity": "Required",
"errorMessage": "Email address is required"
},
"inlineAction": {
"type": "Action.Submit",
"title": "Submit"
}
}
]
}
If you want to get Adaptive Cards to do something they were not designed to do, you will need to write your own renderer code using Adaptive Cards extensibility. You can use this answer and its many linked answers as your guide.
I've found that the usual pattern for these kinds of issues has two parts: come up with your own "schema" for your code to read, and then write the code to read it. If you want a choice set input to populate a certain text input with a certain value when a certain choice is selected, then your schema has three pieces of information: the text input's ID, the value to populate it with, and the choice that triggers it. Since this is a lot of information, it would be ideal if you could have all three of those pieces in their own "populate" object property like this:
{
"type": "Input.ChoiceSet",
"id": "dropdown",
"choices": [
{
"title": "Myself",
"value": "Myself"
},
{
"title": "Other",
"value": "Other"
}
],
"placeholder": "Raise request for",
"populate": {
"target": "email",
"with": "my_email#email.com",
"when": "Myself",
},
},
Unfortunately, Direct Line will strip out additional properties from your Adaptive Card so they'll never reach Web Chat. There is a workaround for that problem where you can preserve your full JSON by tricking Direct Line into thinking it's not an Adaptive Card and then making sure Web Chat knows it's an Adaptive Card when it receives it.
If you don't use the workaround, you will need to find some way of getting those three pieces of information to Web Chat. If don't want your code to be reusable for different cards then you can just hardcode the name of the text input and the choice into your JavaScript so that it doesn't need to be transmitted through the card. If you go the usual route of putting the information in the id property then it could look pretty crowded, and a dynamic ID could be hard for your bot to read after the data is submitted:
"id": "populate_email_when_Myself_with_my_email#email.com",
If the user's email is already stored on the Web Chat side somehow then you won't need to transmit it through the card, and the ID could just be "populate_email_when_Myself". That's a bit less imposing, and it would be easier for your bot to find because it's not dynamically generated. I'll go even further by assuming your client has the email address already and the text input's ID "email" is hardcoded in the JavaScript, so the choice set input ID can just be "populateEmail_Myself".
Once you're ready to write the JavaScript code, I usually like to go with onParseElement so most of my code only gets executed at the beginning as part of a sort of initialization. However, I've discovered that a problem with onParseElement is that you'll only have access to the elements that have already been parsed, so if your text input is parsed after your choice set input then the onParseElement function for the choice set input won't have access to the text input. You could solve that problem by having the function look for an element at the very end of your card so that the function will have access to all the other elements, but my example here just uses onInputValueChanged instead of onParseElement. Note that this means the function will be executed any time any input value is changed in any card, including each time a key is pressed in a text input.
window.AdaptiveCards.AdaptiveCard.onInputValueChanged = input => {
const PREFIX_POPULATE_EMAIL = 'populateEmail_';
if (input.id && input.id.startsWith(PREFIX_POPULATE_EMAIL)) {
// Myself
const targetValue = input.id.slice(PREFIX_POPULATE_EMAIL.length);
// The Adaptive Card object
const card = input.getRootElement();
// The text input with the hardcoded ID
const emailElement = card.getElementById('email');
// Did the user choose "Myself"?
if (input.value == targetValue) {
emailElement.renderedInputControlElement.value = THEIR_EMAIL_ADDRESS;
}
}
}
In many cases you'll need to re-render the element after you modify it by calling emailElement.render(). We don't need to do that in this case because we're changing the value in the rendered element directly with renderedInputControlElement rather than changing the value in the internal unrendered card element. This is a bit hacky because renderedInputControlElement is marked as protected in the TypeScript file, but if you wanted to do things the more official way then I suspect you'd have to rerender the whole card.

How would it be possible that adaptive cards in Microsoft Teams for Android never be cropped (using c#)?

In Microsoft Teams for Windows the Adaptive Cards look like this:
And in Microsoft Teams for Android the same Adaptive Cards look this way:
I'm using LG-files (Microsoft Language Generation files) and Microsoft.Bot.Builder.Dialogs.
Is there a solution to prevent that adaptive cards were being cropped in Microsoft Teams for Android?
Here is the code of the first part:
{
"type": "AdaptiveCard",
"body": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Submit",
"title": "Ja, einverstanden.",
"data": {
"msteams": {
"type": "messageBack",
"text": "Ja, einverstanden.",
"displayText": "Ja, einverstanden."
}
}
}
]
}
]
},
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Submit",
"title": "Nein",
"data": {
"msteams": {
"type": "messageBack",
"text": "Nein",
"displayText": "Nein"
}
}
}
]
}
]
},
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "ActionSet",
"actions": [
{
"type": "Action.Submit",
"title": "Weitere Infos",
"data": {
"msteams": {
"type": "messageBack",
"text": "Weitere Infos",
"displayText": "Weitere Infos"
}
}
}
]
}
]
}
]
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}
Thank you Tim Cadenbach. Your example looks like this on Android:
This means that only the first button was displayed and it was cropped.
On Windows, it Looks like this:
The first and second buttons have been cropped.
All buttons are located one above the other and not side by side.
I considered adding a case distinction and programming other adaptive cards for mobile devices. How can I find out what device it is? With channels from Microsoft.Bot.Connector I can find out that the channel is MS Teams. But how the device?
This is the default behaviour of Mobile adaptive card actions. Adaptive card renders the buttons according to the width of the screens and provides you a scroll bar below to scroll through the buttons.
Updated Answer:
This is a known issue in the MS Teams Mobile App already raised with the team here:
https://github.com/microsoft/AdaptiveCards/issues/3919
Someone is working on it and it should be solved in the next month.

Waterfall model with adaptive cards in v4.0

I'm trying to create a water fall model with the help of Adaptive cards in C# version 4.0.
My scenario is like following:
On loading bot following cards will be shown:
1. SharePoint
2. Azure
3. O365
Once I click on any of them then new set of cards will be shown like:
On selecting "SharePoint" following cards will be shown:
1. Create a Site
2. Create a sub site.
and on selecting any of the above choices a form is called with set of questions like:
1. what is site title
2. site owner
and so on..
UI as shown below:
I tried creating the structure on https://adaptivecards.io/, but couldnt find any relevant code related to this type of scenario.
If any one has done it before please share the documentation or code snippet.
Thanks
Here's a basic card with Input.ChoiceSet:
{
"type": "AdaptiveCard",
"body": [
{
"type": "Container",
"items": [
{
"type": "Input.ChoiceSet",
"id": "first",
"placeholder": "Placeholder text",
"choices": [
{
"title": "SharePoint",
"value": "SharePoint"
},
{
"title": "Azure",
"value": "Azure"
},
{
"title": "O365",
"value": "O365"
}
],
"style": "expanded"
}
]
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Submit"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}
Then, in your bot, follow these answers for dealing with User Input:
Using Adaptive Cards in Waterfall Dialogs
(optional) Dynamically Changing The Card Before Sending
Basically, you'll want to:
Send the card
Capture the card's input by sending a blank text prompt right after sending the card (as explained in the first link)
Use if or switch statements in the next step to determine which card to display next based off of the user's input. You could optionally create the card more dynamically using the second link
The AdaptiveCards Designer is pretty good, but it lacks the ability to set the actions property. You can do so manually, by adding (like I did above):
"actions": [
{
"type": "Action.Submit",
"title": "Submit"
}
],
Using Images
If you'd like to use images instead of a ChoiceSet, you can do something like this:
{
"type": "AdaptiveCard",
"body": [
{
"type": "Container",
"items": [
{
"type": "Image",
"id": "choice1",
"selectAction": {
"type": "Action.Submit",
"title": "choice1",
"data": {
"choice": 1
}
},
"url": "https://acuvate.com/wp-content/uploads/2017/02/Microsoft-Botframework.fw_-thegem-person.png",
"altText": ""
},
{
"type": "Image",
"id": "choice2",
"selectAction": {
"type": "Action.Submit",
"title": "choice2",
"data": {
"choice": 2
}
},
"url": "https://acuvate.com/wp-content/uploads/2017/02/Microsoft-Botframework.fw_-thegem-person.png",
"altText": ""
},
{
"type": "Image",
"id": "choice3",
"selectAction": {
"type": "Action.Submit",
"title": "choice3",
"data": {
"choice": 3
}
},
"url": "https://acuvate.com/wp-content/uploads/2017/02/Microsoft-Botframework.fw_-thegem-person.png",
"altText": ""
}
]
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0"
}
The important part is making sure that the Action.Submit:
Is on the image
Has data that you would use to capture which choice the user selected

Categories

Resources