I followed the proactivemessage sample code (https://github.com/MicrosoftDX/botFramework-proactiveMessages) - and hope that its just something that I overlooked.
I made the following changes
If I publish the site (to azure), send a message to the bot; it will successfully save/over write the blob and then if I call the trigger, it will send me a message from the data in the blob - so all is good till here.
If I republish the site and then try to recall the same trigger (the activity message has already been saved to blob from the first attempt) it fails - giving me a "Service url webchat.botframework.com is not trusted and JwtToken cannot be sent to it."
If I send another message to the bot, then call the trigger again, it successfully send the message again.
It seems it cannot create a direct conversation for some reason if it's not already (recently?) received a message from that channel as this is the line that throws the error:
await connector.Conversations.CreateDirectConversationAsync(botAccount, userAccount)
Any thoughts on what I could be doing wrong?
@dandriscoll?
Hi @zxed, when you're dealing with ServiceUrls across process boundaries, the SDK needs you to tell it whether the ServiceUrl was transmitted in a trusted way.
When you receive and store a message, keep track of whether or not it was trusted:
bool isTrusted = MicrosoftAppCredentials.IsTrustedServiceUrl(activity.ServiceUrl);
// Here are some example lines showing how you could store the message for later
storedMessage.Activity = activity;
storedMessage.IsTrusted = isTrusted;
UploadToBlobStore(storedMessage);
...
Then, when you rehydrate the message, you can tell us to trust the URL.
storedMessage = GetFromBlobStore();
if (storedMessage.IsTrusted)
{
MicrosoftAppCredentials.TrustServiceUrl(storedMessage.Activity.ServiceUrl);
}
Thank you - Can you share what your storedMessage obj looks like?
I was storing the activity object as json in azure.
using (var ms = new MemoryStream())
{
var json = JsonConvert.SerializeObject(activity);
StreamWriter writer = new StreamWriter(ms);
writer.Write(json);
writer.Flush();
ms.Position = 0;
await blockBlob.UploadFromStreamAsync(ms);
}
The storedMessage object is up to you.
It looks like you're just serializing the Activity object, which would not have space to contain this added field. The ResumptionCookie object* is pretty close to what you want. You could store all three in an object like this:
public class StoredMessage
{
public ResumptionCookie ResumptionCookie { get; set; }
public Activity Activity { get; set; }
public bool ServiceUrlIsTrusted { get; set; }
}
Two things:
ResumptionCookie, you probably don't need to store the Activity object as well.ResumptionCookie in a future SDK release, so be aware the name may change soon.Thank you. In what instance would ServiceUrl not need to be trusted? are there some integrations that dont require it?
It should not happen if your bot is properly configured. This is primarily a defense mechanism in case you delete or disable your BotAuthentication attribute. In that situation, we want to detect that the ServiceUrl came in through an unauthenticated endpoint.
Keeping the isTrusted flag connected to the ServiceUrl is our recommended approach for ensuring the URL was securely transmitted.
Thanks.
bool isTrusted = MicrosoftAppCredentials.IsTrustedServiceUrl(activity.ServiceUrl);
if(!isTrusted)
MicrosoftAppCredentials.TrustServiceUrl(activity.ServiceUrl, DateTime.MaxValue);