0
votes

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:

  1. How to configure my Angular app to notify my bot of a new proactive message I want to send.
  2. How to configure the bot to accept some custom parameters (Teams user ID, message).
2

2 Answers

1
votes

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:

  1. Get the Proactive Sample working and dig through the code until you really understand how the API part works.

  2. Get the Teams Sample working, then try to make it message individual users.

  3. 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.

3
votes

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,