I am working on MS Bot Framework Integration with UCMA(Skype For Business OnPremise aka SFB onPrimise) SDK.
I am using directline channel for connection and the Connection is successfully established between two, but when a dialog prompt with Yes, No options is returned From BOT to SFB, and when I send my answer as yes then BOT do not recognize it as my answer. It creates new conversation Id for every single statement. How to overcome this issue?
Below is my code from UCMA
static DirectLineClient client = null;
client = new Microsoft.Bot.Connector.DirectLine.DirectLineClient("DirectLineSecretKey");
botConversation = client.Conversations.NewConversation();
string message = e.TextBody;
Microsoft.Bot.Connector.DirectLine.Models.Message msg = new Microsoft.Bot.Connector.DirectLine.Models.Message
{
FromProperty = "AMOL",
Text = message
};
await client.Conversations.PostMessageAsync(botConversation.ConversationId, msg);
var messages = await client.Conversations.GetMessagesAsync(botConversation.ConversationId, watermark);
InstantMessagingFlow instantMessagingFlow = (InstantMessagingFlow)sender;
watermark = messages.Watermark;
foreach (var m in messages.Messages)
{
if (m.FromProperty != "AMOL")
instantMessagingFlow.BeginSendInstantMessage(m.Text, MyMethod, instantMessagingFlow);
}
I am doing the same and it works for me. The problem in your code is, you create conversation id for each and every request and bot is considering the request as new fresh new request.
Let me know if you need any help on this.
Related
We had some code that has been working for the past 10 months (since it was developed) and just stopped working this afternoon. It's a WebAPI code to send a channel message mentioning the bot and a user, which now is returning "Bad Request. Invalid request body was sent."
If the "Mentions" property is not provided, the call works, and the message is sent without the #mentions. So, I wonder if there was a breaking change in this API that's now expecting a different format for the "Mentions" property.
It's quite simple to reproduce by following the example code found in the Microsoft Graph documentation.
I'm posting here in the hope some fellow dev spots something obvious or is aware of an alternative way of using the API that it might stop complaining, as Microsoft takes forever to reply.
Here's the code we have that can lead me to discover the issue:
private async Task SendMentionToTheBotAsync(GraphServiceClient onBehalfOfClient, string userName, string teamId, string channelId)
{
var supportAgentUser = await onBehalfOfClient.Me.Request().GetAsync();
var chatMessage = new ChatMessage
{
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = $"<at id=\"0\">{Configuration["BotName"]}</at>: This is the start of the conversation between {userName} and <at id=\"1\">{supportAgentUser.DisplayName}</at>."
},
Mentions = new List<ChatMessageMention>
{
new ChatMessageMention
{
Id = 0,
MentionText = Configuration["BotName"],
Mentioned = new IdentitySet
{
Application = new Identity
{
DisplayName = Configuration["BotName"],
Id = Configuration["BotAppId"],
AdditionalData = new Dictionary<string,object>
{
{
"applicationIdentityType", "bot"
}
}
}
}
},
new ChatMessageMention
{
Id = 1,
MentionText = supportAgentUser.DisplayName,
Mentioned = new IdentitySet
{
User = new Identity
{
DisplayName = supportAgentUser.DisplayName,
Id = supportAgentUser.Id,
AdditionalData = new Dictionary<string,object>
{
{
"userIdentityType", "aadUser"
}
}
}
}
}
}
};
await onBehalfOfClient.Teams[teamId].Channels[channelId].Messages
.Request()
.AddAsync(chatMessage);
}
Microsoft Support responded with :
"Thank you for contacting Microsoft Support.
I understand the issue is related to the post messages to Teams. Based on the screenshot, it seems you are using mention to a channel. It's possible that you are using key "conversationIdentityType#odata.type" in your request.
Could you please try to remove "conversationIdentityType#odata.type" key from the request body and try again. It should work. It is because deployment is on the way in the Asia region. Once it's 100% rolled out, this key WILL NOT be entertained in the request."
Removed the key and it worked for me.
Paulo,
Unfortunately i am not a programmer. I am using Graph calls in a Microsoft 365 Power Automate workflow. I have an app that i use to get the Authorisation Bearer token and then post to Teams messages using a graph HTTP action.
Here is the syntax of the HTTP ( purple items are variables if u r not familiar with Flow )
click to view image of Power Automate workflow HTTP action
I have created a Teams bot in .NET Core from following the sample found here: https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/57.teams-conversation-bot
This is working and is running locally with ngrok. I have a controller with a route of api/messages:
[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()
{
// Delegate the processing of the HTTP POST to the adapter.
// The adapter will invoke the bot.
await Adapter.ProcessAsync(Request, Response, Bot);
}
}
I now want to call a POST to api/messages from my Angular client using TypeScript to send a proactive message to a specific Teams user.
I did figure out how to set the ConversationParameters in TeamsConversationBot.cs to a specific Teams user by doing the following:
var conversationParameters = new ConversationParameters
{
IsGroup = false,
Bot = turnContext.Activity.Recipient,
Members = new[] { new ChannelAccount("[insert unique Teams user guid here]") },
TenantId = turnContext.Activity.Conversation.TenantId,
};
but what I'm struggling with is how to build a JSON request that sends the Teams user guid (and maybe a couple other details) to my api/messages route from TypeScript.
How do I go about doing this? What parameters/body do I need to send? I haven't been able to find samples online that show how to do this.
Update below for added clarification
I am building a web chat app using Angular for our customers. What I'm trying to do is send a proactive message to our internal employees, who are using Microsoft Teams, when a customer performs some action via the chat app (initiates a conversation, sends a message, etc.).
I've built a Teams bot using .NET Core using this sample: https://kutt.it/ZCftjJ. Modifiying that sample, I can hardcode my Teams user ID and the proactive message is showing up successfully in Teams:
var proactiveMessage = MessageFactory.Text($"This is a proactive message.");
var conversationParameters = new ConversationParameters
{
IsGroup = false,
Bot = turnContext.Activity.Recipient,
Members = new[] { new ChannelAccount("insert Teams ID here") },
TenantId = turnContext.Activity.Conversation.TenantId,
};
await ((BotFrameworkAdapter)turnContext.Adapter).CreateConversationAsync(teamsChannelId, serviceUrl, credentials, conversationParameters,
async (t1, c1) =>
{
conversationReference = t1.Activity.GetConversationReference();
await ((BotFrameworkAdapter)turnContext.Adapter).ContinueConversationAsync(_appId, conversationReference,
async (t2, c2) =>
{
await t2.SendActivityAsync(proactiveMessage, c2);
},
cancellationToken);
},
cancellationToken);
What I'm struggling with is:
How to configure my Angular app to notify my bot of a new proactive message I want to send.
How to configure the bot to accept some custom parameters (Teams user ID, message).
It sounds like you've got some progress with pro-active messaging already. Is it working 100%? If not, I've covered the topic a few times here on stack overflow - here's an example that might help: Programmatically sending a message to a bot in Microsoft Teams
However, with regards -trigging- the pro-active message, the truth is you can do it from anywhere/in any way. For instance, I have Azure Functions that run on their own schedules, and pro-active send messages as if they're from the bot, even though the code isn't running inside the bot at all. You haven't fully described where the Angular app fits into the picture (like who's using it for what), but as an example in your scenario, you could create another endpoint inside your bot controller, and do the work inside there directly (e.g. add something like below:)
[HttpPost]
public async Task ProActiveMessage([FromQuery]string conversationId)
{
//retrieve conversation details by id from storage (e.g. database)
//send pro-active message
//respond with something back to the Angular client
}
hope that helps,
Hilton's answer is still good, but the part about proactively messaging them without prior interaction requires too long of a response. So, responding to your latest comments:
Yes, the bot needs to be installed for whatever team the user resides in that you want to proactively message. It won't have permissions to do so, otherwise.
You don't need to override OnMembersAddedAsync; just query the roster (see below).
You don't need a conversation ID to do this. I'd make your API, instead, accept their Teams ID. You can get this by querying the Teams Roster, which you'll need to do in advance and store in a hash table or something...maybe a database if your team size is sufficiently large.
As far as required information, you need enough to build the ConversationParameters:
var conversationParameters = new ConversationParameters
{
IsGroup = false,
Bot = turnContext.Activity.Recipient,
Members = new ChannelAccount[] { teamMember },
TenantId = turnContext.Activity.Conversation.TenantId,
};
...which you then use to CreateConversationAsync:
await ((BotFrameworkAdapter)turnContext.Adapter).CreateConversationAsync(
teamsChannelId,
serviceUrl,
credentials,
conversationParameters,
async (t1, c1) =>
{
conversationReference = t1.Activity.GetConversationReference();
await ((BotFrameworkAdapter)turnContext.Adapter).ContinueConversationAsync(
_appId,
conversationReference,
async (t2, c2) =>
{
await t2.SendActivityAsync(proactiveMessage, c2);
},
cancellationToken);
},
cancellationToken);
Yes, you can modify that sample. It returns a Bad Request because only a particular schema is allowed on /api/messages. You'll need to add your own endpoint. Here's an example of NotifyController, which one of our other samples uses. You can see that it accepts GET requests. You'd just need to modify that our build your own that accepts POST requests.
All of this being said, all of this seems like it may be a bigger task than you're ready for. Nothing wrong with that; that's how we learn. Instead of jumping straight into this, I'd start with:
Get the Proactive Sample working and dig through the code until you really understand how the API part works.
Get the Teams Sample working, then try to make it message individual users.
Then build your bot that messages users without prior interaction.
If you run into trouble feel free to browse my answers. I've answered similar questions to this, a lot. Be aware, however, that we've switched from the Teams Middleware that I mention in some of my answers to something more integrated into the SDK. Our Teams Samples (samples 50-60) show how to do just about everything.
Question
I have a simple Bot for MS Teams developed in C# with the Bot Builder SDK 3.15.0.0 targeting .NET framework 4.7.1.
When mentioned, it retrieves the Jira ticket Ids in the message and returns a single reply with a list of Cards, each one displaying a summary of a Jira Issue.
I'd like to know if it's possible to not populate the activity feed when sending the reply with the card attachments as it's not needed for my use case.
Example
This is how I usually build the reply to a user message
var reply = activity.CreateReply();
reply.AttachmentLayout = AttachmentLayoutTypes.List;
reply.Attachments = thumbnailCards;
await context.PostAsync(reply);
And this is what I tried after reading the docs at https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/activity-feed#rest-api-sample
var reply = activity.CreateReply();
reply.AttachmentLayout = AttachmentLayoutTypes.List;
reply.Attachments = thumbnailCards;
reply.ChannelData = JsonConvert.SerializeObject(new
{
notification = new
{
alert = false
}
});
await context.PostAsync(reply);
I was hoping that setting the ChannelData with notification.alert = false would just disable the notifications, but it actually doesn't display any message.
Have you tried using the Teams nuget package: https://www.nuget.org/packages/Microsoft.Bot.Connector.Teams
var reply = activity.CreateReply();
reply.ChannelData = JObject.FromObject(new TeamsChannelData()
{
Notification = new NotificationInfo(false)
});
Source for this package can be found here: https://github.com/OfficeDev/BotBuilder-MicrosoftTeams/
The alert you are getting in the activity feed is simply the "someone replied to your message" alert and is nothing special coming from the bot. This notification in the activity feed cannot be disabled as of now. Other team members won't receive this alert in activity feed unless they are following the same channel.
Sending notification using Rest API is designed to work for 1:1 chat.
I am creating a bot to proactively start a conversation with an account I have never had a previous conversation with. I have created another controller that I am posting to and doing the following steps:
public class OutboundController : ApiController {
public HttpResponseMessage Post([FromUri] int id, [FromBody] OutboundData outboundData) {
MicrosoftAppCredentials.TrustServiceUrl(outboundData.ServiceUrl);
//create conversation
var connector = new ConnectorClient(new Uri(outboundData.ServiceUrl));
var botAccount = new ChannelAccount { Id = outboundData.FromAccountId, Name = outboundData.FromAccountName };
var toAccount = new ChannelAccount { Id = outboundData.ToAccountId, Name = outboundData.ToAccountName };
if(!MicrosoftAppCredentials.IsTrustedServiceUrl(outboundData.ServiceUrl)) {
throw new Exception("service URL is not trusted!");
}
var conversationResponse = connector.Conversations.CreateDirectConversation(botAccount, toAccount);
var client = new BuslogicClient();
var confirmData = client.GetOutboundData(id);
var greetingMessage = CreateGreetingMessage(confirmData);
var convoMessage = Activity.CreateMessageActivity();
convoMessage.Text = greetingMessage;
convoMessage.From = botAccount;
convoMessage.Recipient = toAccount;
convoMessage.Conversation = new ConversationAccount(id: conversationResponse.Id);
convoMessage.Locale = "en-Us";
connector.Conversations.SendToConversationAsync((Activity)convoMessage);
string message = string.Format("I received correlationid:{0} and started conversationId:{1}", id, conversationResponse.Id);
var response = Request.CreateResponse(HttpStatusCode.OK, message);
return response;
}
When I call connector.Conversations.CreateDirectConversation I am getting the following exception: Additional information: Authorization for Microsoft App ID [ID] failed with status code Unauthorized and reason phrase 'Unauthorized'. If I do this with appId and password blank everything works fine in the channel emulator. I've tried providing the MicrosoftAppCredentials to the constructor of the ConnectorClient, but that has no affect. I've read on other threads that the service URL must be trusted so I used MicrosoftAppCredentials.TrustServiceUrl.
versions I am using:
BotBuilder 3.5.3
Channel Emulator 3.0.0.59
The use-case for my bot is to post to the outbound controller with some user info to create a proactive message to be sent out (specifically SMS). If the user responds to my message it will be intercepted by the messages controller and passed to my dialogs for further processing and conversation responses on that same channel.
I've also taken a look at: https://github.com/Microsoft/BotBuilder/issues/2155 but don't quite understand solution described in the comments or if it even pertains to the issue I'm trying to solve.
Any suggestions or help would be appreciated!
You need to pass credentials explicitly to connector:
var credentials = new MicrosoftAppCredentials("YoursMicrosoftAppId", "YoursMicrosoftAppPassword");
var connector = new ConnectorClient(serviceUrl, credentials);
Updated
I am developing a Skype bot with 1:1 conversation with Bot Framework.
In that I have a WebHook method which will call from an external service and sends message to my bot, then my bot will send that message to a skype user.
The following code is for v1 in message controller along with api/messages post method
public async Task<Message> Post([FromBody]Message message){}
[Route("~/api/messages/hook")]
[HttpPost]
public async Task<IHttpActionResult> WebHook([FromBody]WebHookMessage message)
{
if (message.Type == "EmotionUpdate")
{
const string fromBotAddress = "<Skype Bot ID here>";
const string toBotAddress = "<Destination Skype name here>";
var text = resolveEmoji(message.Data);
using (var client = new ConnectorClient())
{
var outMessage = new Message
{
To = new ChannelAccount("skype", address: toBotAddress , isBot: false),
From = new ChannelAccount("skype", address: $"8:{fromBotAddress}", isBot: true),
Text = text,
Language = "en",
};
await client.Messages.SendMessageAsync(outMessage);
}
}
return Ok();
}
I will call above WebHook from another service, so that my bot will send messages to the respective skype user.
Can anyone please help me how can I achieve the same in V3 bot framework?
I tried the following but not working
const string fromBotAddress = "Microsoft App ID of my bot";
const string toBotAddress = "skype username";
WebHookMessage processedData = JsonConvert.DeserializeObject<WebHookMessage>(message);
var text = resolveEmoji(processedData.Data);
using (var client = new ConnectorClient(new Uri("https://botname.azurewebsites.net/")
, "Bot Microsoft App Id", "Bot Microsoft App secret",null))
{
var outMessage = new Activity
{
ReplyToId = toBotAddress,
From = new ChannelAccount("skype", $"8:{fromBotAddress}"),
Text = text
};
await client.Conversations.SendToConversationAsync(outMessage);
}
But it is not working, finally what I want to achieve is I want my bot send a message to a user any time how we will send message to a person in skype.
The following code works, but there are some things that are not that obvious that I figured out (tested on Skype channel)
When a user interacts with the bot the user is allocated an id that can only be used from a specific bot..for example: I have multiple bots each using a skype channel. When I send a message from my skype user to bot A the id is different than for bot B. In the previous version of the bot framework I could just send a message to my real skype user id, but not anymore. In a way it simplifies the whole process because you only need the recipient's id and the framework takes care of the rest, so you don't have to specify a sender or bot Id (I guessed all that is linked behind the scenes)
[Route("OutboundMessages/Skype")]
[HttpPost]
public async Task<HttpResponseMessage> SendSkypeMessage(SkypePayload payload)
{
using (var client = new ConnectorClient(new Uri("https://skype.botframework.com")))
{
var conversation = await client.Conversations.CreateDirectConversationAsync(new ChannelAccount(), new ChannelAccount(payload.ToSkypeId));
IMessageActivity message = Activity.CreateMessageActivity();
message.From = new ChannelAccount();
message.Recipient = new ChannelAccount(payload.ToSkypeId);
message.Conversation = new ConversationAccount { Id= conversation.Id };
message.Text = payload.MessageBody;
await client.Conversations.SendToConversationAsync((Activity)message);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
I'm not sure I understand what you're trying to do. If you'd like to answer a message (activity), try something like this:
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var reply = activity.createReply(text, "en");
await connector.Conversations.ReplyToActivityAsync(reply);
Activity.createReply switches the From and Recipient fields from the incoming activity. You can also try setting these field manually.
UPDATE
You need to create a ConnectorClient to the Skype Connector Service, not to your bot! So try with the Uri http://skype.botframework.com it might work.
However, I don't think you can message a user on Skype without receiving a message from it in the first place (i.e. your bot needs to be added to the user's contacts). Once you have an incoming message from the user, you can use it the create replies, just as described above.
WebHookMessage processedData = JsonConvert.DeserializeObject<WebHookMessage>(message);
var text = resolveEmoji(processedData.Data);
var client = new ConnectorClient(new Uri(activity.serviceUrl));
var outMessage = activity.createReply(text);
await client.Conversations.SendToConversationAsync(outMessage);
activity is a message received from the given user earlier. In this case, activity.serviceUrl should be http://skype.botframework.com, but generally you should not rely on this.
You can try to create the activity (outMessage) manually; for that, I'd recommend inspecting the From and Recipient fields of a message coming from a Skype user and setting these fields accordingly. However, as mentioned before, your bot needs to be added to the user's contacts, so at this point it will have received a message from the user.