BotFramework - How to pass the language from the DirectLine API - botframework

I'm coding a bot in two languages (en, es) which will always be accessed via DirectLine API.
The documentation says that:
The localization language is determined by the current thread's CurrentUICulture and CurrentCulture.
What is the proper way to pass the language to the BOT from the DirectLine API, so can be getted by CurrentCulture?

I haven't found out a proper way to do it, but I use a workaround.
When you give your user an ID, add the culture. Like this:
id: 'en-'+ idGeneratedByYou
Then from the controller:
var culture = activity.From.Id.Split('-')[0];
Finally, do a switch and depending it is en or es:
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("es-ES");
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("es-ES");
I know this is not the best way, but maybe it will work out for you.

Related

BotFramework TurnContext SendActivityAsync "Object reference not set to an instance of an object"

I'm trying to use botframework v4 in Azure Functions Powershell. I have this working successfully by just calling the raw REST APIs and using the botframework types like Activity.
Now I'm trying to actually use the framework and adapters proper. However, when I call SendActivityAsync on the Turn Context, I get "Object reference not set to an instance of an object" and really no way to find out where that's coming from.
Is there anything obviously missing here, or perhaps another approach to using BotFrameWork adapter I'm missing? I'm trying to adapt the EchoBot sample to Powershell, as the ConsoleBot sample doesn't call http back to the bot framework.
Assume that Activity is real, I know that's not where my null is coming from(it wouldn't let me create the turncontext if it was)
$activity = [JsonConvert]::DeserializeObject(($QueueItem -replace '^---JSON---',''), [activity])
#Only Process Message Activities for now
if ($activity.Type -ne 'message') {return}
$reply = $activity.CreateReply("I got your message that says $($activity.text)")
$appCredentials = [MicrosoftAppCredentials]::new('c28d55e3-fb0b-4367-b4a6-f00959a54e5b','n=_y:3LsJo/MYAPPSECRETP5')
$botFrameworkAdapter = [BotFrameworkAdapter]::new($appCredentials, [AuthenticationConfiguration]::new())
$turnContext = [TurnContext]::new($botFrameworkAdapter, $Activity)
$turnContext.SendActivityAsync($reply).GetAwaiter().GetResult()

Customizing Adaptive Card appearance using RenderedAdaptiveCards inside bot framework SDK

I am developing a Bot using Microsoft Bot Framework. I am using Adaptive Cards for displaying flights to users but they have a lot of limitations on their appearance. I am trying to render the adaptive card from one of the dialogs within my bot framework by creating a adaptive card renderer using my own hostconfig.json and then attaching the Html of my adaptive card back to the chat window. But its not working :(
public static Attachment CreateFlight(Flight flight)
{
var renderedAdaptiveCard = AdaptiveCardRenderer
.RenderCard(new AdaptiveCard
{
Body = new List<AdaptiveElement>
{
new AdaptiveContainer {Items = CreateFlightAdaptiveElements(flight)}
},
Actions = new List<AdaptiveAction>
{
new AdaptiveShowCardAction
{
Card = new AdaptiveCard
{
Body = new List<AdaptiveElement>
{
},
Actions = new List<AdaptiveAction>
{
new AdaptiveSubmitAction
{
Title = "Select",
Data = flight.Segments.Select(x => $"{x.Airline} {x.FlightNo}")
.Aggregate((i, j) => i + "/" + j),
}
},
BackgroundImage = new Uri($"{DomainUrl}/Images/ac_background.jpg")
},
Title = "Select"
},
},
BackgroundImage = new Uri($"{DomainUrl}/Images/ECEFF1.png")
});
var attachment = new Attachment
{
ContentType = "application/html",
Content = renderedAdaptiveCard.Html
};
return attachment;
}
Am I trying something that is impossible here ? How to change the default grey looks of my bot ? My primary channels would be Skype, Slack etc so I don't have plans to integrate this to a Web Chat. Kindly help me with this regard.
The idea behind Adaptive Cards is to allow each channel to render the cards in a way that's specific to that channel. A card "adapts" to any environment that might support it. While Adaptive Cards offer a lot of flexibility, the bot can only do so much because it's ultimately the channel that's in charge of rendering the card.
Card Authors describe their content as a simple JSON object. That
content can then be rendered natively inside a Host Application,
automatically adapting to the look and feel of the Host.
For example, Contoso Bot can author an Adaptive Card through the Bot
Framework, and when delivered to Skype, it will look and feel like a
Skype card. When that same payload is sent to Microsoft Teams, it will
look and feel like Microsoft Teams. As more host apps start to support
Adaptive Cards, that same payload will automatically light up inside
these applications, yet still feel entirely native to the app.
Users win because everything feels familiar. Host apps win because
they control the user experience. And Card Authors win because their
content gets broader reach without any additional work.
As you probably know, the RenderedAdaptiveCard type is meant to be used in client-side code. That means it can help you if you want to make your own channel for example, but it's not really meant to be used in a bot. Your code isn't working because there is no HTML attachment type and most channels don't support HTML at all. You can find more information in this question and this GitHub issue.
Hopefully you can achieve the appearance you're looking for using the tools available to you, such as images and links.

Using MS Teams as Channel: Authentification Dialog (GetTokenDialog class from Microsoft.Bot.Builder.Dialogs) doesn't popup

How can I use the new authentification feature in Bot Builder with MS Teams?
There seems to be an issue with Teams (see Login user with MS Teams bot or https://github.com/Microsoft/BotBuilder/issues/2104), seems if this is not considered in GetTokenDialog?
Is there any chance to get around this?
Just found the reason why it won't work with Teams. In method Microsoft.Bot.Connector.Activity.CreateOAuthReplyAsync(), Parameter asSignInCard has to be set to True for MSTeams, then, the line new CardAction() { Title = buttonLabel, Value = link, Type = ActionTypes.Signin } has to be changed to new CardAction() { Title = buttonLabel, Value = link, Type = ActionTypes.OpenUrl } because MS Teams can obviously not deal with Action type Signin. Hope, the MS developers will fix that method soon.
There are a few things you need to do to get this to work. First you need to create a manifest file for your bot in teams and whitelist token.botframework.com. That is the first problem.
From teams itself in AppStudio you create a Manifest. I had to play around with this a little bit. In AppDetails... Let it generate a new ID. Just hit the button. The URLs really don't matter much for testing. The package name just needs to be unique so something like com.ilonatag.teams.test
In the bots section you plug in your MS AppId and a bot name. This is a the real MSAPPID from your bots MicrosoftAppId" value=" from web.config in your code.
Ok now in "finish->valid domains" I added token.botframework.com and also the URL for my bot just in case. so something like franktest.azurewebsites.net
This part is done but you are not quite done... in your messages controller you need to add this since Teams sends a different verification than the other clients.
if (message.Type == ActivityTypes.Invoke)
{
// Send teams Invoke along to the Dialog stack
if (message.IsTeamsVerificationInvoke())
{
await Conversation.SendAsync(message, () => new Dialogs.RootDialog());
}
}
It took me a bunch of going back and forth with Microsoft to get this sorted out.
This is a known problem using OAuthCard in MS Teams. To solve it, you can change the Button ActionType from signIn to openUrl using this solution on github

How can I support other languages using FormFlow?

I built a bot and it's working well, I'm using FormFlow to complete a questionnaire. I need the commands working in Spanish, but it only works in English (help, quit, reset...), except in the emulator.
Using the emulator and changing the Locale to "es" is working:
When I type "ayuda", the help is showed. It's ok.
In the Bot profile page, the bot was published in spanish (using "es"):
The bot was published in Skype, Facebook Messenger, Slack and Telegram.
When I use the bot in Android with language in "Estados Unidos - Español" or "España - Español" and type "ayuda" or other command in spanish, the bot answers the input in english with "'Ayuda' is not a [field] option" message, but when the input is "Help" it's working well.
Is there something I'm missing?
I use ngrok for review the messages exchanged between Emulator and the bot, using the Locale field (with es, es-US, es-PA, es-ES, etc) the messages in spanish is working.
After this, I write a little command in the bot for get the Locale, this field return an empty value ever (with es, en, etc).
Finally, I set the locale in the MessagesController in the Post method.
activity.Locale = "es-US";
The bot is working in spanish like I want.
Is this the best solution?
I had the same problem. Fixed it by changing the thread's culture in the form builder:
public static IForm<YourDialogForm> BuildForm()
{
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("es-AR");
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("es-AR");
return new FormBuilder<YourDialogForm>()
//your code
.Build();
}
disclaimer: not sure if it's the best place to change the culture

facebookredirect.axd in multi tenant application

I have one facebook mvc3 application that actually consists of several facebook apps.
Every app has it's own 'virtual path' (defined in the global.asax)
routes.MapRoute("Default", "{ns}/{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional, ns = UrlParameter.Optional });
This means they have all use the same physical app, but have different paths: mydomain.com/facebookapp1, mydomain.com/facebookapp2, ...
The problem is that when I call for user authentication, the facebook page is called with a return url of mydomain.com/facebookredirect.axd. Facebook then decides this url is not part of that specific app, so it returns an error message.
So my question: where does the Facebook C# SDK get this facebookredirect.axd link from? I would like to change it to mydomain.com/facebookapp1/facebookredirect.axd. Does anyone know how to achieve this?
Thanks in advance!
May I suggest to separate your applications into multiple IIs applications?
app1.mydomain.com
app2.mydomain.com
etc..
Each app has its own host header.
That way they are isolated and aren't dependent on each other in terms when you want to deploy/update changes.

Resources