Bot Framework Channel Emulator has invalid channel ID? - c#

I'm using the C# Bot Framework library to retrieve some data from the Bot State Service. Whenever channelId == "emulator" in the code below, it fails with a 400 Bad Request. It looks like both Emulator versions 3.0.0.59 and 3.5.27 use this channel ID. Here's the returned payload:
{
"error": {
"code": "BadArgument",
"message": "Invalid channel ID"
}
}
Note that if I change channelId to something else like "skype", it works as expected.
var credentials = new MicrosoftAppCredentials(id, password);
this.botState = new BotState(new StateClient(credentials));
var channelId = activity.ChannelId;
await botState.GetUserDataAsync(channelId, activity.From.Id);

Received this answer from the Bot Framework team:
For emulator they need to use the activity’s serviceurl when create the state client. Builder automatically does that in the connector client factory:
https://github.com/Microsoft/BotBuilder/blob/master/CSharp/Library/Microsoft.Bot.Builder/ConnectorEx/IConnectorClientFactory.cs#L86
if (IsEmulator(this.address))
{
// for emulator we should use serviceUri of the emulator for storage
return new StateClient(this.serviceUri, this.credentials);
}
That error is from state.botframework.com (which is the default endpoint for stateclient) since emulator is not a valid channelid for the state service.

Related

Smart home report state SYNC new device | Requested entity was not found. [404]

I've implemented the HomeGraph API with the help of the package Google.Apis.HomeGraphService.v1 (1.50.0.2260)
It seems to work fine as well, the ReportStateAndNotification function works fine on the query, execute, and some sync requests.
But when I add a new device to my system through our app and a SYNC request is sent to Google and comes in our backend, the HomeGraph API will return an exception when sending this sync request..
-> The sync request does not throw an exception when I modify a device name in our app. It only occurs when new devices are added.
I've searched through google and multiple StackOverflow posts.. But I'm probably missing something. Most posts say check the API key etc but then the ReportStateAndNotification function should always fail, not only when the sync request comes from Google to our backend.
Could anyone point me in the right direction?
Function that is used for sync requests:
public static void Send(Dictionary<string, object> deviceStateList, string requestId, string googleCustomerId)
{
string deviceIdList = String.Format("({0})", string.Join(", ", deviceStateList.Keys));
try
{
var jsonFilePath = _appSettingsRetriever.PrivateGoogleAuthenticationFile;
string scope = "https://www.googleapis.com/auth/homegraph";
using (var stream = new FileStream(jsonFilePath, FileMode.Open, FileAccess.Read))
{
GoogleCredential credentials = GoogleCredential.FromStream(stream);
if (credentials.IsCreateScopedRequired)
credentials = credentials.CreateScoped(scope);
HomeGraphServiceService service = new HomeGraphServiceService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials
});
var request = new ReportStateAndNotificationRequest
{
AgentUserId = googleCustomerId,
RequestId = requestId,
Payload = new StateAndNotificationPayload
{
Devices = new ReportStateAndNotificationDevice
{
States = deviceStateList
}
}
};
_log.Debug($"Sending to HomeGraph for devices: {deviceIdList} customer: {googleCustomerId} requestId: {requestId}");
DevicesResource.ReportStateAndNotificationRequest rp = service.Devices.ReportStateAndNotification(request);
ReportStateAndNotificationResponse resop = rp.Execute();
}
}
catch (Exception ex)
{
_log.Error($"Exception in ReportToHomeGraph for Customer: {googleCustomerId}. DeviceList: {deviceIdList}. JsonPath: {_appSettingsRetriever.PrivateGoogleAuthenticationFile} Exception: {ex}.");
}
}
Exception:
2021-09-24 14:16:13,547 [110] ERROR ReportToHomeGraph
Exception in ReportToHomeGraph for Customer: 05. DeviceList: (
fe965e6a-21ad-425f-b594-914bf63510a9,
1cc0ee97-a87f-44c5-a3e3-a39d159ee193,
618cdf94-2b31-434f-b91e-00837d155d4a
).
JsonPath: C:/myfile.json Exception: The service homegraph has thrown an exception:
Google.GoogleApiException: Google.Apis.Requests.RequestError
Requested entity was not found. [404]
Errors [
Message[Requested entity was not found.] Location[ - ] Reason[notFound] Domain[global]
]
at Google.Apis.Requests.ClientServiceRequest`1.<ParseResponse>d__35.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Google.Apis.Requests.ClientServiceRequest`1.Execute()
at BusinessLogic.GoogleAssistant.TokenService.HomeGraph.ReportToHomeGraph.Send(Dictionary`2 deviceStateList,
String requestId, String googleCustomerId) in C:\Repos\GoogleAssistant
.TokenService\HomeGraph\ReportToHomeGraph.cs:line 57.
When users add a new device, the first step you need to do is to issue a Request Sync to Google. This indicates the set of devices for that user has changed, and you need a new Sync request to update the data in homegraph. Google will follow this by delivering a Sync intent to your fulfillment endpoint, which you can respond with the updated set of devices.
Getting a 404 when calling Request Sync might indicate your Service Account Key might be invalid, or the agent user id you target might be wrong. Otherwise getting an error for your Sync Response might indicate it’s structured incorrectly. You can find out more about how to structure it in our examples.

Firebase: server response does not contain a JSON object

I am trying to run a ASP.NET Core API to send FCM push notifications.
The API works with Firebase SDK. The code is basically the one in the documentation:
Initialize the default app, configPath being the JSON project configuration
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.FromFile(configPath), //JSON con API Key credentials
});
Example of the payload I am sending
//Send a message to the device corresponding to the provided
//registration token.
//var message = new Message()
//{
// Data = new Dictionary<string, string>()
// {
// { "score", "850" },
// { "time", "2:45" },
// },
// Token = registrationToken,
// Notification = new Notification
// {
// Body = "Test"
// }
//};
The async task I am sending
string response = await FirebaseMessaging.DefaultInstance.SendAsync(payload).ConfigureAwait(false);
Everything works OK on local (push notifications are being send), configuration seems to be alright but the deployed API running on my server returns the following error:
Server runs on Windows 10, has internet connectivity and already has other APIs (not FCM related) working fine.
As a ServiceUnavailable error I have already checked if its a Firebase problem but then again if it is Firebase problem it wouldn't work on local, right?

Send notification from C# to web Cause Error Auth error from APNS or Web Push Service

I am trying to send notification to my web app using Firebase. I successfully followed the steps mentioned here to setup a JavaScript Firebase Cloud Messaging client app. Then successfully I got user approval and subscription token. Here is the code
subscribeToNotifications() {
const messaging = firebase.messaging();
messaging.requestPermission().then(function () {
console.log('have permission');
return messaging.getToken();
})
.then(function(token){
console.warn('Messaging Token: ' + token)
})
.catch(function (err) {
console.error(err);
})
}
Then I am trying to use this token to send notification from my C# console. So, here is what I did so far:
First: I generated a private key file for my service account following these steps
In the Firebase console, open Settings > Service Accounts.
Click Generate New Private Key, then confirm by clicking Generate Key.
Securely store the JSON file containing the key.
Second: I created a .net core C# console app and did the following to initialize firebase.
Installed the firebase admin package
Install-Package FirebaseAdmin -Version 1.8.0
Wrote the following code to initialize the firebase app
static void Main(string[] args)
{
FirebaseApp.Create(new AppOptions()
{
Credential =
GoogleCredential.FromFile("D:\\__\\myprojectcred.json"),
});
Console.WriteLine("Initialized");
SendMessageAsync().Wait();
}
The application successfully initialized.
However, when I tried to send the message by calling SendMessageAsync it fails in this line
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
The code is as follow:
public static async System.Threading.Tasks.Task SendMessageAsync()
{
// This registration token comes from the client FCM SDKs.
var registrationToken = "eRXeB4adi0k:APA91HGlcqh8Ow…nlrO8";
// See documentation on defining a message payload.
var message = new Message()
{
Data = new Dictionary<string, string>()
{
{ "score", "850" },
{ "time", "2:45" },
},
Token = registrationToken,
};
// Send a message to the device corresponding to the provided
// registration token.
string response = await FirebaseMessaging.DefaultInstance.SendAsync(message);
// Response is a message ID string.
Console.WriteLine("Successfully sent message: " + response);
}
The error is
FirebaseMessagingException: Auth error from APNS or Web Push Service
Please help to figure out the problem.
Update:
The notification is sent to the server successfully when I tested it with Firefox client, so now the problem is with Edge browser only.

botframework on teams channel 1:1 Authentication AAD integrated

I'm looking to connect my bot on teams channel but i didn't know the way to secure this for use only in our domains (organization).
I have test to look (authentication AAD) for the Azure Web App but it's doesn't work on teams or on webchat because the endpoint adresse it's not redirected.
I have test to implement AUTH card but it doesn't work on teams.
Note : I'm using botframework C# api BotBuilder 3.15.2.2
I have look other "ask" like :
AAD authentication in Microsoft teams for Bot Framework
Is it possible to access custom tabs in 1:1 chats in MS Teams?
https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/authentication/auth-flow-bot
https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/authentication/auth-bot-AAD
https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/authentication/authentication
https://tsmatz.wordpress.com/2016/09/06/microsoft-bot-framework-bot-with-authentication-and-signin-login/
Sincerely,
Pascal.
Edit :
I have implemented the solution sugested by Adrian, below was a piece of C# code that implement this on the MessasController.cs (Post Function):
Note ==> Adding access for localhost use
//https://stackoverflow.com/questions/51090597/botframework-on-teams-channel-11-authentication-aad-integrated
string tenantIdAAD = "";
try
{
tenantIdAAD = activity.GetChannelData<TeamsChannelData>().Tenant.Id;
}
catch (Exception exception)
{
tenantIdAAD = "";
}
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
if ([AAD_TenantID].TenantIdAAD.Equals(tenantIdAAD) || activity.ServiceUrl.StartsWith("http://localhost") )
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog().LogIfException());
}
else
{
await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Access Denied"));
}
The incoming message contains information that you can use to identify the user. A message looks like this:
{
...
"from": {
"id": "29:1XJKJMvc5GBtc2JwZq0oj8tHZmzrQgFmB39ATiQWA85gQtHieVkKilBZ9XHoq9j7Zaqt7CZ-NJWi7me2kHTL3Bw",
"name": "Richard Moe",
"aadObjectId": "ae361bee-9946-4082-99dc-6994b00ceebb"
},
"channelData": {
"tenant": {
"id": "72f988bf-86f1-41af-91ab-2d7cd011db47"
}
}
}
The channelData.tenant.id identifies the organization (O365 tenant) that the user is part of, so you can look at that and reject messages that aren't from ones that you expect.
The message also has the AAD object ID of the sender in from.aadObjectId. The auth flow in the links above is useful if you need tokens to provide to other services so you can act on behalf of the user, but if all you need is the user's tenant and identity, the message has all you need.
(Remember to authenticate the incoming request first, before trusting any information in the message.)

Microsoft.Bot.Connector - The To Address refers to {} which is not a known

I'm developing a bot to be used with the email channel (Office 365).
I'm struggling to implement a "Starting a new conversation with the user", i.e. the bot should initiate conversation with the user(s) after receiving certain triggers.
I'm referencing the example available on http://docs.botframework.com/.
var connector = new ConnectorClient();
Message newMessage = new Message();
newMessage.From = new ChannelAccount() { Address = "[email the bot is registered with]", Name = "Awesome Bot", ChannelId = "email", IsBot = true };
newMessage.To = new ChannelAccount() { Address = user.Email, Name = $"{ user.FirstName } {user.LastName}", ChannelId = "email", IsBot = false };
newMessage.Text = message;
newMessage.Language = "en";
connector.Messages.SendMessage(newMessage);
The bot is live in Azure and registered with the framework.
When I invoke the above code, looks like the connector is sending a request to api.botframework.com, but receives a status code 404 back. I'm also seeing the following error message:
The To Address refers to [user email] which is not a known
It sounds like the error is cut off. I'm not sure what I'm doing wrong here.
We were worried about spammers abusing the ability to send email through our servers, so we limited the ability to send a message to people who are not already in the conversation or users of the system. Our thoughts are that we will enable this functionality as part of being approved in our directory or as for paid clients.

Categories