Error sending message to WebChat via DirectLine - botframework

I have a bot deployed in Azure. Uses the latest >net bot framework, (v3).
The front-end uses the vanilla WebChat. I am trying to send an event from the BOT TO THE CLIENT, in order to trigger a wipe of the webchat visible history.
I'm getting the more than useless 502 error when my bot tries to send the event message.
The JS to setup the web chat and directline on my front end is:
var botConnection = new BotChat.DirectLine({
secret: {secret removed..becuase secret},
//token: params['t'],
//domain: params['domain'],
webSocket: "true" // defaults to true
});
BotChat.App({
bot: bot,
botConnection: botConnection,
resize: 'detect',
user: user,
chatTitle: false,
showUploadButton: false
}, document.getElementById('bot'));
//backchannel communication setup
botConnection.activity$
.filter(function (activity) {
return activity.type === 'event' && activity.name === 'clearChatHistory';
})
.subscribe(function (activity) {
console.log('"clearChatHistory" received');
clearChatHistory();
});
function clearChatHistory() {
$(".wc-message-wrapper").remove();
}
The idea here is that my bot code will create a message of type 'activity' with the value = 'clearChatHistory'. This fire the code on my client.
The code for sending this message is:
internal static async Task SendClearChatHistoryEvent(Activity activity)
{
Trace.TraceInformation($"Utility::SendClearChatHistoryEvent");
Activity clearMessage = activity.CreateReply();
clearMessage.Type = "event";
clearMessage.Value = "clearChatHistory";
Trace.TraceInformation(JsonConvert.SerializeObject(clearMessage));
Trace.TraceInformation($"Utility::SendClearChatHistoryEvent::ServiceURL:{activity.ServiceUrl}");
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
await connector.Conversations.SendToConversationAsync(clearMessage);
}
The bot fail is happening at the 'SendToConversationAsync' call
The closest thing I get to an error is on the client side
"https://directline.botframework.com/v3/directline/conversations/5OSJJILizNqGG4H7SaV6fQ/activities 502 (Bad Gateway)"
The Visual Studio output window displays
'Microsoft.Rest.TransientFaultHandling.HttpRequestWithStatusException'
and 'Microsoft.Bot.Connector.ErrorResponseException
exceptions
Any insights on what I might be doing wrong or whats happening otherwise here would be greatly appreciated.

You're setting the value on the event but checking the name. If you use this as the filter it should work:
.filter(activity => activity.type === 'event' && activity.value === 'clearChatHistory')
Regarding the bad gateway however, I am not sure, as I was not seeing this occur with your code on my system.

I figured out what the problem is. First, there was a bug in my code example which Mark B pointed out. However, that was not the source of the problem but it did help me to get to the real issue.
The Bad Gateway problem wasn't really a good indicator of the problem either. I had to do a lot of Trace writing and stepping through code to finally notice what was happening. I'll try to describe the problem so you all can learn from my boneheaded mistake.
The understand the problem, you need to understand what this line of code is doing
Activity clearMessage = activity.CreateReply();
CreateReply() creates a new Activiy from an existing one. When it does that, it swaps the values of From and Recipient. This is because you want to reply to the person the original message comes from. Make 100% total sense.
The problem, for me, was my original message was ALSO created by calling CreateReaply() in a previous dialog. SO, I basically created a new message to be sent to myself (or the bot in this case). I need the message to to to the chatbot user, not the bot.
When the bot framework attempted to send itself a message it excepted and failed. Why it got the bad gateway error I dont exactly know and will continue to research that.
To fix this, I changed my upstream code to use
var newMessage = context.MakeMessage()
instead of the CreateReaply(). This does not swap From and Recipient.
Everything is now flowing along very nicely. My code will now force a wipe of the visible chat history in my WebChat client.

Related

Failed to connect (500) to bot framework using Direct Line

We have a bot running in Azure (Web App Bot) that I'm trying to embed on a website. The bot is based of the Bot Builder V4 SDK Tamplate CoreBot v4.9.2. At first I used the iframe to embed the bod. This worked but didn't provide the features we need, so now im changing it to use DirectLine.
My code on the webpage looks like this:
<script crossorigin="anonymous"
src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<div id="webchat" role="main"></div>
<script>
(async function () {
const res = await fetch('https://[my bot name here].azurewebsites.net/.bot/v3/directline/tokens/generate',
{
method: 'POST',
headers: new Headers({
'Authorization': "Bearer [my token here]"
})
});
const { token } = await res.json();
window.WebChat.renderWebChat(
{
directLine: await window.WebChat.createDirectLineAppServiceExtension({
domain: 'https://[my bot name here].azurewebsites.net/.bot/v3/directline',
token
})
},
document.getElementById('webchat')
);
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
</script>
After some struggles I managed to fetch a token from https://[my bot name here].azurewebsites.net/.bot/v3/directline.
And I can see the chat window on my webpage, but is says connecting for a while then it changes to Taking longer than usual to connect, like this:
In the Chrome console there is an error saying Failed to connect Error: Connection response code 500. When I check Chrome's Network tab I can see that the token generated completed with status 200 and that the websocket connection is open, like this:
----------EDIT---------
I just noticed that when go to https://[my bot name here].azurewebsites.net/.bot using a webbrowser, the resulting json is
{"v":"1.0.0.0.55fa54091a[some key?]","k":true,"ib":false,"ob":false,"initialized":true}
ib and ob should be true but are false, maybe this is part of the problem.
----------EDIT 2---------
OK so now I'm starting to go crazy.
Ashish helped me and at some point the ib and ob were true. They were true for most of yesterday. At some point yesterday they turned false for a short while (no more than 2 hours). I checked if someone had triggered the release pipeline but no recent releases. After that ib and ob magically turned true again and connecting to the direct line worked again.
Now this morning ib and ob were false again. And again no recent releases. I don't know what is causing this.
Does anybody know what's going on here or how to fix this? How do I find what causes ib and ob to be false?
Any help is appreciated! Thanks in advance. If you need more information, just ask and I'll post it.
If the ib and ob values displayed by the *.bot endpoint are false this means the bot and the Direct Line app service extension are unable to connect to each other.
Make sure you verify below things:
Double check the code for using named pipes has been added to the
bot.
Confirm the bot is able to start up and run at all. Useful
tools are Test in WebChat, connecting an additional channel, remote
debugging, or logging.
Restart the entire Azure App Service the bot
is hosted within, to ensure a clean start up of all processes.
Please check troubleshooting guide, it seems updated today. (still old date reflected some how, not sure why)

How do I debug channel data in bot framework?

I have a bot where I've recently started passing channel data (user info) in from my directline client but now this makes it really hard to debug/test code that relies on this channel data.
Is there a way to have the Bot Framework Emulator send channel data or is there a better way to debug in this situation?
Emulator doesn't have an easy, built-in way to send custom channelData. There's a few different ways you can (kind of) do this, though:
Debug Locally
As #EricDahlvang mentioned (I forgot about this), you can debug any channel locally
WebChat
Emulator is built in WebChat, so the output will be the exact same. However, you miss some of the debugging functionality from Emulator.
Clone a WebChat Sample
Edit index.html with http://localhost:3978/api/messages and your channelData
Run npx serve
Navigate to http://localhost:5000
Modify Messages In OnTurnAsync()
This would only be for testing/mocking purposes and you'd want to ensure this doesn't go into production, but you can modify incoming messages inside OnTurnAsync() and manually add the channelData.
Something like:
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
var activity = turnContext.Activity;
activity.ChannelData = new
{
testProperty = "testValue",
};
You could even make it happen with only specific messages, with something like:
if (turnContext.Activity.Text == "change channel data")
{
activity.ChannelData = new
{
testProperty = "testValue",
};
}
There's a lot of different options with this one, you just need to make sure it doesn't go into production.

How to switch Dialogs in BotFramework SDK3 C#

I'm trying to add a timeout Dialog using proactiveMessages. If user doesn't reply to [A dialog], [timeout dialog] comes out. So I think timeout dialog should be the current dialog. But do I to close other dialog [A dialog]?
According this, it seems context.EndConversation was not working in MS Teams. Of course I have tried again. It is still not working.
I also tried the way below. But it seems not working either.
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, context.Activity.AsMessageActivity()))
{
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(default(CancellationToken));
var stack = scope.Resolve<IDialogStack>();
stack.Reset();
await botData.FlushAsync(default(CancellationToken));
}
Any suggestions about changing the dialog?
There are two methods of redirecting dialog flow within a C# bot.
you can use context.Forward() to send a user to a new dialog starting with a message that you are currently processing:
await context.Forward(new NewOrderDialog(), this.ResumeAfterNewOrderDialog, message, CancellationToken.None);
or you can use context.call() to send a user to a new dialog and start from scratch there:
context.Call(new AgeDialog(this.name), this.AgeDialogResumeAfter);
The "ResumeAfter" functions can be defined anywhere (including a function within the new dialog itself) and setting these to where you would like to redirect the user after they have finished with your timeout dialog will allow you to determine the flow.

Which event type is triggered when a slack app is installed onto a workspace for the first time?

I'm trying to build an app that does something when it is first installed onto a workspace, eg: Ping every team member.
I couldn't find an event type that gets triggered upon app install:
https://api.slack.com/events
Is there a way to make this happen?
I think there might be a misunderstanding of the events concepts here. Events are always directly linked to one specific Slack app and needs to be processed by that very app. There is no such thing as "general" events for things happening on a workplace, like a new app being installed. Ergo there is no event for app installation.
Nevertheless you can implement the functionality you mentioned with Slack, e.g. pinging all team members once an app is first installed. All you need to do is include this function in the installation process of your Slack app and e.g. start pinging after the installation process is complete and the app verified that it was the first installation to this workspace. You do not need an event for that.
This is a partial answer because I was wondering the same thing and wanted to share what I found. On this oauth tutorial, it has the following code snippet:
app.get('/auth', function(req, res){
if (!req.query.code) { // access denied
return;
}
var data = {form: {
client_id: process.env.SLACK_CLIENT_ID,
client_secret: process.env.SLACK_CLIENT_SECRET,
code: req.query.code
}};
request.post('https://slack.com/api/oauth.access', data, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Get an auth token
let oauthToken = JSON.parse(body).access_token;
// OAuth done- redirect the user to wherever
res.redirect(__dirname + "/public/success.html");
}
})
});
I believe instead of the line res.redirect(__dirname + "/public/success.html"); at that point you can make a request to ping everyone or even call a function to do so directly there, and it will trigger immediately once the app has been installed.

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

Resources