Monday, 7 February 2022

Working with the Microsoft Graph communications API in a Microsoft Teams meeting app

Following up on my previous post about Microsoft Teams meeting apps, let's now have a look at how we can invoke the Microsoft Graph in our meeting app. 

Specifically, we will be using the Microsoft Graph communications API to get all meeting participants.

When I was first looking at this scenario, I thought it would be quite straightforward as this seems to be quite a common use case for meeting apps. However, I was in for a bit of a surprise as that did not turn out to be the case. 

My thinking was that I would get a meetingId as part of the Teams JS SDK context object and I would use this meetingId to get details from the Graph. But it turns out that the meetingId which the Teams JS SDK provides is completely different than the meetingId recognised by that Microsoft Graph

To fetch the meetingId which the Graph recognises, we have to introduce the Bot Framework SDK to the mix and exchange the Teams JS SDK meetingId for the Graph meeting Id. 

So let's see how to achieve this using code:

1) Using Teams JS SDK, get user id, meeting id, tenant id

This bit is straightforward, in your Teams tab you can get the meeting context using the Teams JS SDK:

2) Use Bot SDK to get Graph meeting ID from the Teams meeting id

Next, from your Teams Bot, call the /v1/meetings/{meeting-id} API. Couple of things you should know beforehand: 

This API is currently in developer preview. This means that it will only work for when the Microsoft Teams Clients have been switched to preview mode.

Secondly, we have to turn on Resource Specific Consent (RSC) for your app and request the required scopes. More details on both points here:

Once you have everything setup, you can call the API to get the meeting details:

The response would contain a details object with an msGraphResourceId property. This will be the meeting id which would work with the Graph API.

3) Use Graph API to get meeting participants from Graph meeting id

Finally, from the msGraphResourceId, we can make a regular call to the Graph to get the meeting details. Specifically, we will call the /onlineMeetings/{meetingId} endpoint:

In this case, we will get the meeting participants:

Make sure you have the correct Delegated or Application permissions granted to the Azure AD app registration you are using for authenticating to the Graph.

This is not an ideal situation as you might not have a requirement for a Bot in your Teams app and might be building a tab for example. In this case, Yannick Reekmans has written a post for you here:  

That's it for now. Hope you find this helpful when exploring meeting apps right now.

Thursday, 13 January 2022

Working with Apps for Microsoft Teams meetings

Microsoft Teams meetings extensions or "Apps for Teams meetings" are the newest entry in the Microsoft Teams extensibility story. They can be used to build custom experiences right into the meeting experience. Meeting participants are able to interact with the custom experiences either before, during or after the meeting. To know more about apps for Teams meetings, a great place to start is the Microsoft docs:

Pre-meeting and Post-meeting experiences

The pre and post meeting experiences are not too different than what we are used to when building Tabs for Teams. The basic structure remains the same with the only different thing being that the Teams SDK provides the meeting specific APIs when invoked from a meeting app. These APIs can be used to get meeting details like participants and meeting context in our app. More information on the APIs here:

In-meeting experiences

When it comes to the In-meeting experiences, there are two main areas: The side panel and the in meeting dialog box (also known as content bubble). The side panel is used to show custom experiences while the meeting is in progress

And the in-meeting dialog box (or content bubble) is used to show content, prompt or collect feedback from the users during the meeting:

I should mention here that the In-meeting experiences only work in the Teams desktop and mobile clients as of now. They don't work in the Teams web browser interface at the time of this writing. To me this is the biggest challenge for using them in production.

Now that's enough introduction of the concepts, let's take a look at how to actually build these experiences and what are the moving pieces when building them. The Microsoft docs do provide some great step by step tutorials for each of the use cases. 

In this post we will look at the In-meeting dialog box. We will take a look at the Microsoft's code sample and walk through it. You can find the code sample here:

1) Configure an Azure Bot and enable Teams Channel

Create a bot in Azure and configure the endpoint which should receive the Teams events:

Next, add the Teams channel so that the bot is able to talk to Microsoft Teams:

2) Update the Teams manifest

For the In-meeting dialog box, we don't have to make any special changes in the manifest. We just need to make sure that since the dialog box will be shown via the bot, our Teams app manifest should have the bot configured as part of it. 

3) Create an Azure AD app registration for the app

When we created the Azure Bot, a new Azure AD app registration was created behind the scenes as well. Grab the client id and client secret from this app as we would need it later to add to our bot config

4) Start the ngrok tunnel and update the code sample:

To debug locally, you will need to setup an ngrok tunnel to your local machine. More details here:

And in the code sample, update the bot client id and client secret along with the ngrok tunnel url:

5) In meeting dialog code:

The way to bring up an in-meeting dialog is to use the regular Bot Framework turnContext.SendActivityAsync(activity) code but with updated Teams channel data:

You will notice that in the In-meeting dialog url, there is a reference to {_config["BaseUrl"]}/ContentBubble 

This means that the contents of the in-meeting dialog have to be hosted in our app. This is good news as that means we have complete control over what is displayed in the dialog. In this code sample, the contents are hosted in an MVC view:

And once everything fits together, we can see the sample code running to show an In-meeting dialog launched in the context of a meeting:

Hope this helps, and thanks for reading!