I'm using the following pattern used in multiple samples and it works fine in WebChat and Emulator channels but when I connected my bot to the Facebook channel it sends a duplicate welcome message.
protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
{
var welcomeText = "Hello and welcome!";
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Recipient.Id)
{
await turnContext.SendActivityAsync(MessageFactory.Text(welcomeText, welcomeText), cancellationToken);
}
}
}
Any ideas?
I haven't worked a lot with the OnMembersAdded, so I also still have some missing understanding there, and I haven't worked with facebook bots at all, so this is just a simple guess in case it can help - it might be that facebook is sending multiple users in the membersadded list in this case. Have you tried debugging and seeing what comes through? I would guess that possibly you don't need to do a "turnContext.SendActivityAsync" in every loop of the foreach - maybe just do a check if you need to send any message (i.e into a boolean) and then just send a single one after the loop if the boolean is true.
It seem to be a bug in the bot framework.
I was able to workaround it with changed condition:
if (!member.Id.EndsWith(turnContext.Activity.Recipient.Id))
The bug is reported here
https://github.com/microsoft/BotFramework-Services/issues/165
Related
I have implemented an OAuth sign in flow for my teams bot using Microsoft AAD v2 and the OAuthPrompt dialog with the help of this guide.
My dialog definition is as followed:
AddDialog(new OAuthPrompt(
nameof(OAuthPrompt),
new OAuthPromptSettings
{
ConnectionName = configuration["ConnectionName"],
Text = "Please Sign In",
Title = "Sign In",
Timeout = 300000,
EndOnInvalidMessage = true
}));
and I initiate it as the first step of my root dialog
private async Task<DialogTurnResult> LoginPromptAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
return await stepContext.BeginDialogAsync(nameof(OAuthPrompt), null, cancellationToken);
}
I'm also passing the invoke activity using the OnTeamsSigninVerifyStateAsync function
protected override async Task OnTeamsSigninVerifyStateAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken)
{
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}
It is working fine on the desktop client, but while trying to sign in from my mobile device, the bot receives the response without the token.
The authentication flow is almost similar to the one implemented in this sample
I tried adding 'login.microsoftonline.com' as well as 'token.botframework.com' to validDomains property in the manifest to no avail.
I also added
devicePermissions": [ "openExternal" ]
to the manifest, again to no avail.
I also tried debugging the bot locally and found that the sign in invoke activity from a mobile device results in the following 404 error
UPDATE: I found that the sample (from which I picked up the authentication flow) also fails to login through mobile, I'm unable to figure out whether the problem is something from my side or from the sample code being outdated.
It'd be super helpful if somebody could clone the sample and see if results are the same.
I started with Hello World Bot(ICommandHandler), I modified it
Now I try to process the response from the adaptive card
Already checked it out https://learn.microsoft.com/en-us/microsoftteams/platform/bots/bot-basics?tabs=csharp
I still can't understand - Where I am supposed to catch the submit action?
Adaptive Card
Since you mentioned you used Teams Toolkit C#, I assume you are using Teams Toolkit for Visual Studio.
Current Teams Toolkit and its SDK do not have built-in support for Adaptive Cards action handling. So you need to directly use Bot Framework SDK to write your own ActivityHandler to handle the card actions.
public class TeamsBot : ActivityHandler
{
protected override async Task<InvokeResponse> OnInvokeActivityAsync(ITurnContext<IInvokeActivity> turnContext, CancellationToken cancellationToken)
{
// Handle card action
if (turnContext.Activity.Name == "adaptiveCard/action")
{
// Handle your action response
var cardJson = await File.ReadAllTextAsync("Resources/ActionResponseCard.json", cancellationToken).ConfigureAwait(false);
var response = JObject.Parse(cardJson);
var adaptiveCardResponse = new AdaptiveCardInvokeResponse()
{
StatusCode = 200,
Type = "application/vnd.microsoft.card.adaptive",
Value = response
};
return CreateInvokeResponse(adaptiveCardResponse);
}
return CreateInvokeResponse(null);
}
}
You also need to use Action.Execute instead of Action.Submit which is the newer Universal Actions for Adaptive Cards. It is a unified action model across platforms.
Also see this GitHub issue to learn more.
You can checkout this more complete example in teams samples repo.
I have a MS Teams bot. I have installed the bot for couple of users in tenant. Now when I'm starting conversation, for few users it is responding and few it is not.
I investigated further and found out that for users who are getting reply from bot, the serviceurl is "https://smba.trafficmanager.net/in/".
For users who are not getting reply from bot, the serviceurl is "https://smba.trafficmanager.net/apac/".
Exception message: Operation returned an invalid status code 'NotFound'
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
var reply = activity.CreateReply();
reply.Text = "Hi there";
await context.PostAsync(reply);
}
This sounds like it's possibly a TrustServiceUrl Issue (despite the 500 vs 401 error message).
You can fix it by adding all of your ServiceUrls to the list of trusted URLs:
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
var activity = await result as Activity;
var serviceUrl = activity.ServiceUrl;
MicrosoftAppCredentials.TrustServiceUrl(serviceUrl);
var reply = activity.CreateReply();
reply.Text = "Hi there";
await context.PostAsync(reply);
}
This should ensure that your bot "trusts" the ServiceUrl of any message that it receives.
Let me know how that goes. I'm 90% sure this is the issue, but it might not be.
Here's a link to the library, if that helps. Otherwise, browsing these issues should help.
Note to others:
This "Trust Service URL Issue" doesn't apply to just Teams. This happens for lots of other URLs when trying to use Proactive messaging. Just replace serviceUrl with whatever is appropriate for your use case. And yes, if you're using multiple channels, you can add multiple URLs when using MicrosoftAppCredentials.TrustServiceUrl() by calling it multiple times.
Here's the method definition. Note: you can add expiration for this, as well.
I've submitted a PR for this, which so far has resulted in some updated docs
I was able to convert my EchoBot to interact with QnAMaker as per instructions here on my local development system but when I publish the same using kudu repo (tried using Azure DevOps service Ci/CD pipeline but it does not work [in preview] because after deployment the bot just hangs on portal and never able to test it on web chat.. so gave up and used recommended kudu repo), I do not get the correct answer to my response. For every question I send, it is unable to detect the QnAMaker service. And I am returning error message from the code that says no QnaMaker answer was found.
How do I troubleshoot to identify the cause of this?
My bot file seems to be working fine locally and I am able to get the answer from QnAMaker locally but not after publishing the code to my Web App Bot in Azure.
I feel like Botframework V4 (using .net) is not very straight forward and the instruction on the portal (document) is still kind of evolving or sometime incomprehensible.
Here is the snapshot from my emulator while testing the chat locally:
And here is the snapshot of production endpoint (using the same questions on portal) with my error msg from OnTurnAsync function:
My .bot has all the services defined and local bot is working fine.
This is the code in my ChatBot class:
public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
// Handle Message activity type, which is the main activity type for shown within a conversational interface
// Message activities may contain text, speech, interactive cards, and binary or unknown attachments.
// see https://aka.ms/about-bot-activity-message to learn more about the message and other activity types
if (turnContext.Activity.Type == ActivityTypes.Message)
{
// Get the conversation state from the turn context.
var state = await _accessors.CounterState.GetAsync(turnContext, () => new CounterState());
// Bump the turn count for this conversation.
state.TurnCount++;
// Set the property using the accessor.
await _accessors.CounterState.SetAsync(turnContext, state);
// Save the new turn count into the conversation state.
await _accessors.ConversationState.SaveChangesAsync(turnContext);
// Echo back to the user whatever they typed.
//var responseMessage = $"Turn {state.TurnCount}: You sent '{turnContext.Activity.Text}'\n";
//await turnContext.SendActivityAsync(responseMessage);
// QnAService
foreach(var qnaService in _qnaServices)
{
var response = await qnaService.GetAnswersAsync(turnContext);
if (response != null && response.Length > 0)
{
await turnContext.SendActivityAsync(
response[0].Answer,
cancellationToken: cancellationToken);
return;
}
}
var msg = "No QnA Maker answers were found. Something went wrong...!!";
await turnContext.SendActivityAsync(msg, cancellationToken: cancellationToken);
}
else
{
await turnContext.SendActivityAsync($"{turnContext.Activity.Type} event detected");
}
}
I am digging through all the great new stuff in v3 of the bot framework. One of the things that I am trying to do is create a dialog that responds with cards. But I cannot find a sample that shows how to do this.
I've tried to monkey with it on my own but haven't had much luck. In most of their code samples for Dialogs you cast the Activity object you get in your Post to an IMessageActivity class. Then when you respond you do so with just plain text. All the examples with cards have you create an Activity class. However because I've cast it to IMessageActivity I can't use the CreateReply method. And if I can't do that then when I create an Activity I get an error that the 'activityId' cannot be null.
Any advice, thoughts, or insight would be greatly appreciated.
Thanks in advance!
I added this code to my dialog:
protected override async Task MessageReceived(IDialogContext context, IAwaitable<IMessageActivity> item)
{
_message = (Activity)await item;
await base.MessageReceived(context, item);
}
[field: NonSerialized()]
private Activity _message;
[LuisIntent("Ping")]
public async Task Ping(IDialogContext context, LuisResult result)
{
Activity replyToConversation = _message.CreateReply("Should go to conversation, with a carousel");
replyToConversation.Recipient = _message.From;
replyToConversation.Type = "message";
replyToConversation.AttachmentLayout = "carousel";
.
.
.
await context.PostAsync(replyToConversation);
context.Wait(MessageReceived);
}
I got it working in the emulator but not in Skype but I guess my problem is this one Rich Card attachments are not showing on web chat or Skype