I've raised a bug item against the C# Bot Builder project on GitHub but to be honest I can't really get to the bottom of whether this is a bug with the framework or a sporadic problem originating on the Facebook side.
We have been building the bot for a couple of months and have been using in development and staging exvironments extensively and have not seen this issue once.
So we go live with our first customer and boom. This issue starts occuring.
Value cannot be null. Parameter name: invalid activity-missing From.Id
And also:
Value cannot be null. Parameter name: invalid activity-missing
Conversation.Id
The chats that produced this issue were started by users coming to the bot via the messenger web page and the Web Chat Plugin.
The users in both instances had used the "Get Started" button thus opting in to the chat. This opting in provides the bot with access to the users basic profile information.
Understandably this is pretty odd and I have been entirely unable to reproduce this issue in any testing in any of our environments (we have Dev, Staging and Live).
Has anyone else seen a similar issue?
What did you do to work around it?
At the moment since I cannot reproduce it anywhere I can't really close the bug or even have a vague level of confidence in it not happening again.
If your bot is designed with the Activity Handler, as demonstrated in the Samples-work-in-progress branch, you can add some code to the controller to log the entire Request.Body:
[Route("api/messages")]
[ApiController]
public class BotController : ControllerBase
{
private readonly IBotFrameworkHttpAdapter Adapter;
private readonly IBot Bot;
public BotController(IBotFrameworkHttpAdapter adapter, IBot bot)
{
Adapter = adapter;
Bot = bot;
}
[HttpPost]
public async Task PostAsync()
{
Request.EnableBuffering();
using (var buffer = new MemoryStream())
{
await Request.Body.CopyToAsync(buffer);
buffer.Position = 0L;
using (var bodyReader = new JsonTextReader(new StreamReader(buffer, Encoding.UTF8)))
{
Debug.Print(BotMessageSerializer.Deserialize(bodyReader).ToString());
buffer.Position = 0L;
}
}
Request.Body.Position = 0;
await Adapter.ProcessAsync(Request, Response, Bot);
}
}
This should provide more information on what type of message is being sent to the bot. My guess is that it has something to do with a Facebook Messenger specific web hook you have subscribed to. For instance, I don't think 'message_echoes' are currently sent to the bot with a .From or conversation.Id. However, we have recently modified our Connector Service to include these: the release should be within the next few weeks.
Related
I am using the following sample / article to Manage a Long-running operation in MS Teams Bot.
https://learn.microsoft.com/en-us/azure/bot-service/bot-builder-howto-long-operations-guidance?view=azure-bot-service-4.0
In step 5, a DirectLineClient is being created and an Event Activity is sent to Bot using PostActivityAsync.
var responseActivity = new Activity("event");
responseActivity.Value = originalActivity;
responseActivity.Name = "LongOperationResponse";
responseActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
var directLineSecret = Environment.GetEnvironmentVariable("DirectLineSecret");
using(DirectLineClient client = new DirectLineClient(directLineSecret))
{
var conversation = await client.Conversations.StartConversationAsync();
await client.Conversations.PostActivityAsync(conversation.ConversationId, responseActivity);
}
However, I need the above sample to work for MS Teams Bot and not the DirectLineClient.
I used Microsoft.Bot.Connector.ConnectorClient but StartconversationAsync and PostActivityAsync methods are not available.
I tried the methods available in Microsoft.Bot.Connector.ConnectorClient
connectorClient.Conversations.CreateConversationAsync(conversationparameters)
connectorClient.ConversationsCreateDirectConversationAsync(botAccount, userAccount, (Activity)newActivity);
connectorClient.Conversations.SendToConversationAsync(conversationid, (Activity)newActivity);
But all the methods failed with Bad Requestwith the error as seen in the Response:
{"error":{"code":"BadArgument","message":"Unknown activity type"}}
The newActivity is created as below:
var messagnewActivity = new Activity("event");
newActivity.Value = originalActivity;
newActivity.From = new ChannelAccount("GenerateReport", "AzureFunction");
newActivity.Type = "event";
newActivity.Conversation = new ConversationAccount { Id = originalActivity.Conversation.Id };
newActivity.ChannelId = originalActivity.ChannelId;
Can someone please suggest how do I pass the Activity (Event Activity type) to MS Teams Bot.
Thanks
Gagan
I'm not really familiar with Direct Line, but I think it's effectively an -alternative- type of bot to Teams, so if you're trying to do this inside Teams, it explains the issue. In principle, the basic idea is quite simple though:
you store state somehow (e.g. in memory or in a database) to indicate that the long running operation is in progress for the user
when the long-running process is complete, your code (which could live OUTSIDE your bot, e.g. in an Azure Function) can send the user a message AS IF IT WAS the bot - this is called Pro-Active Messaging and you can read more about it at https://learn.microsoft.com/en-us/graph/teams-proactive-messaging.
This is to inform you that I was facing the same issue sometime before then I found a tweak in the code while debugging. when it calls twice recursively then the Activity Id is the same as the previous one. you can check if the activity id is the same then return the request else go with it.
So i created a bot in azure and downloaded it. The free 1000 calls from LUIS reached its limit. I created a subscription in azure portal (I did do the docker container something). Followed this guide until step 6. When i click the endpoint url and query directly in the browser it is working fine.
I added it to the bot via Bot Emulator by clicking + sign in services and adding the bot model there. But when i run bot i get the title error. I noticed in the .bot file the authoring key and subscription key added by the bot emulator is the same.
So i changed the subscription key to the one of the keys generated by azure and still the same error. I have tried reseting the authoring key still same and deleting my luis.ai account and created a new one. (still same email because that is the one logged in azure portal.) and still the same.
Here are some pictures for reference and the error.
I also tried testing it in luis.ai and got this result.
but when i check it is set to the new resource.
Here is a pic of the bot file after adding luis via Bot emulator. It has same authoring key and subscription key (still forbidden)
so i changed it now with subscription key (still forbidden).
Here it is working properly when tested directly in the URL.
For reference:
azure portal
luis.ai
and the error
How i add luis in the bot.
Here is the code for the bot service.
using System;
using System.Collections.Generic;
using Microsoft.Bot.Builder.AI.Luis;
using Microsoft.Bot.Configuration;
namespace Microsoft.BotBuilderSamples
{
public class BotServices
{
public BotServices(BotConfiguration botConfiguration)
{
foreach (var service in botConfiguration.Services)
{
switch (service.Type)
{
case ServiceTypes.Luis:
{
var luis = (LuisService)service;
if (luis == null)
{
throw new InvalidOperationException("The LUIS service is not configured correctly in your '.bot' file.");
}
var endpoint = (luis.Region?.StartsWith("https://") ?? false) ? luis.Region : luis.GetEndpoint();
var app = new LuisApplication(luis.AppId, luis.AuthoringKey, endpoint);
var recognizer = new LuisRecognizer(app);
this.LuisServices.Add(luis.Name, recognizer);
break;
}
}
}
}
public Dictionary<string, LuisRecognizer> LuisServices { get; } = new Dictionary<string, LuisRecognizer>();
}
}
I am trying to solve this for 4 days already. Thanks!
Thank you for all of the images. That is a HUGE help! Here's the problem:
By default, your code looks for the AuthoringKey in this section (second line):
var endpoint = (luis.Region?.StartsWith("https://") ?? false) ? luis.Region : luis.GetEndpoint();
var app = new LuisApplication(luis.AppId, luis.AuthoringKey, endpoint);
var recognizer = new LuisRecognizer(app);
this.LuisServices.Add(luis.Name, recognizer);
Since your .bot file still has the authoringKey set to the one that starts with ad9c..., which has hit its limit, your bot keeps running into the 403 error.
So, in your .bot file, replace that authoringKey with one of your endpointKeys (they start with 12ccc... or b575...).
I understand your confusion with this, especially since this requires you putting an endpointKey in your authoringKey property. I know there's some changes on the horizon to how LUIS bots will use keys, but those are probably a month or more out.
Alternatively, you can change:
var app = new LuisApplication(luis.AppId, luis.AuthoringKey, endpoint);
to:
var app = new LuisApplication(luis.AppId, luis.SubscriptionKey, endpoint);
Note: If you make either of these changes, LUIS can only query (which is usually fine), since Authoring Keys do everything else (see reference, below)
References
These are not so much for you as much as others that might come across this.
Authoring vs. Endpoint Keys
Key Limits
Troubleshooting LUIS 403 Errors
You really need to be able to send raw json at facebook to take advantage of all of the facebook messenger features but I see no way to do that in the MS bot SDK. (version 4). Here is what I think should work, but no luck. If I set the Text property of a reply activity it just shows up as text on messenger (as expected). If I set the ChannelData property with a string no exceptions are thrown but facebook messenger shows no response message. Given what a huge platform FB Messenger is you would think this was a priority in the SDK but I see nothing about it.
if (turnContext.Activity.Type == ActivityTypes.Message)
{
try
{
if((turnContext.Activity.ChannelId == Channel.Channels.Facebook)|| (turnContext.Activity.ChannelId == Channel.Channels.Emulator))
{
string rsp = "{\"attachment\":{\"type\":\"template\",\"payload\":{\"template_type\":\"button\",\"text\":\"What do you want to do next?\",\"buttons\":[" +
"{\"type\":\"web_url\",\"url\":\"https://www.messenger.com\",\"title\":\"Visit Messenger\"}]}}}";
Activity reply = turnContext.Activity.CreateReply();
_logger.LogInformation(rsp);
//reply.Text = rsp; // display message as actual message to messenger
// reply.ChannelData = rsp; // fails request finishes on the MS bot service side, but nothing at all shows on messenger
reply.ChannelData = JsonConvert.DeserializeObject(rsp); // WORKS!
await turnContext.SendActivityAsync(reply);
.... // IN MY ORIGINAL POST THERE WAS AN ERROR IN THE JSON STRING and I got the full answer a minute later... see answer below.
My bad on this. The original post had an error in the rsp string but I also took a look at the sdk source and realized they wanted an object at ChannelData, not a string.... so I deserialized it and stuffed the object to channeldata and it started working. Few posts on this in SDK version 4 so hoping this helps someone. My wall needs some repair after me pounding my head against it all day. – Fred Covely just now
I am trying to use the Microsoft Bot Framework DirectLine API to read and add messages to existing conversations between other users and my bot. From what I've read I believe this should be possible when using the master-secret but it's just not working for me. I'm using a WebAPI to try and access two of my existing conversations (on Facebook & Skype) as follows:
[HttpPost]
[Route("remind")]
public string Remind()
{
var secret = System.Configuration.ConfigurationManager.AppSettings["secret"];
var uri = new Uri("https://directline.botframework.com/");
var creds = new DirectLineClientCredentials(secret);
DirectLineClient client = new DirectLineClient(uri, creds);
Conversations convs = new Conversations(client);
var conversationIDs = new string[] { "0000000000000000-0000000000000000", "00:0123456789abcdefghijklmnopqrstuvwxyz0123456789-A-_0123456798ABCDEF" }; // Existing Facebook & Skype conversations
// Send a message to each conversation:
foreach (var conversationID in conversationIDs)
{
Message message = new Message(conversationId: conversationID, fromProperty: "My Bot", text: "Hey dude, remember that thing!");
Console.WriteLine(message.Text);
convs.PostMessage(conversationID, message); // FAILS - This executes but doesn't do anything.
}
// Try reading the messages from a conversation (just to test if it's working):
string waterMark = null;
var set = convs.GetMessages(conversationIDs[0], waterMark); // FAILS - This fails with a 404 not found.
waterMark = set.Watermark;
return "Done :-)";
}
It fails silently calling PostMessage() and fails with a 404 for the GetMessages(). I seem to be doing the right thing, the bot is live etc and works very well in Facebook & Skype separately from the DirectLine API. It only works if I create a new conversation using the DirectLine API, I can then access its messages and post new messages to it.
This question sort of helps but doesn't quite tell me what to do to fix it:
Difficulty accessing messages in an existing conversation in Microsoft Bot Framework
Any help would be much appreciated.
Thanks
For security reasons, you can't use DirectLine to spy on messages from another conversation. For the scenario you describe (escalating to a human) there a number of different ways to approach this. One is to have your bot broker conversations between the accounts (i.e. Facebook End User <-> Your Bot <-> Facebook Support Person). Each is talking to the bot, and the bot passes the message through to the other user. (Could also be Facebook User <-> Your Bot <-> Skype User) Your bot would have to store last n messages to provide context. Alternatively, I've seen folks build their own customer support chat interface using direct line that sits on the far side. Hope this helps
I have added a vanilla mobile service, selecting the defaults all the way. It is a .Net backend, using a new 20MB DB on an existing server I use in the North Europe DC. I created a blank Windows Store App, added the MobileServices nuget package and then followed the instructions to connect my MobileService to my app by adding the MobileServicesClient to my App.xaml class. Then I added a button with an event handler. The handler calls an async function to insert a TodoItem object into the database.
App.xaml.cs
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://???.azure-mobile.net/",
"???");
I have replaced the URI and Token with ???. The one I used came from my Azure Portal for this Mobile Service.
MainPage.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
CreateItem();
}
private async void CreateItem()
{
TodoItem item = new TodoItem { Text = "Sort This", Complete = false };
try
{
await App.MobileService.GetTable<TodoItem>().InsertAsync(item);
}
catch(MobileServiceInvalidOperationException ex1)
{
Debug.WriteLine(ex1.Message);
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
When I run this code and click the button a MobileServiceInvalidOperationException is raised:
"{"The request could not be completed. (Not Found)"}"
I am using VS2013, with Service Pack 2 installed and WindowsAzure.MobileServices 1.2.3.
The MobileService is running as I can navigate to https://MyMobileService.azure-mobile.net/ but, if I click Check It Out, I am asked to Authenticate (MyMobileService is not the actual Uri).
The post request looks ok, but the response is a 404.
I have been working on this all day, including using Windows Phone, with no luck...
I know I must be doing something wrong, or there is an issue with Azure in Northern Europe, but I can't sort it out.
Any help much appreciated.
Jason.
I had the same issue awhile ago. I switch from .net backend to javascript. Also, make sure your mobileservice and db schema match.