This post supplements my earlier session at the Galactic Collaboration Summit recently held virtually. My session title was Getting Started with Microsoft Azure Functions where I covered exactly what it says.. “getting started” but I also did a few demos one high level and the second demonstrated how to use both Visual Studio for Mac as well as Visual Studio 2019 to create Azure Functions under a few scenarios including Microsoft Graph and Microsoft Teams. In this post I will give you an in depth walk through of how to work with Azure Functions and the Microsoft Graph to include working with Contacts and Teams.
The scenario is simple enough as explained in the session, imagine I ‘Fabian Williams’ as a speaker would like to interact with my session attendees after my presentation. Previously when sessions were done more ‘in person’ this was easy right? Step away from the lectern and hold a conversation, and even then, what if we needed to take the conversation offline and delve deeper, what then? Furthermore, as we find ourselves in a pandemic where we need to maintain ‘social distance’ and conferences become virtual, what then? Well, here comes Azure Functions and Microsoft 365 to the rescue by allowing us to create solutions to exchange Contact information as well as capture that encounter in a Microsoft Teams conversation.
This open source solution is located here in a Github repo for your convenience. The solution starts off with a Microsoft Form with anonymous access which triggers a Microsoft Flow.
The Azure Functions magic happens upon submit where the solution performs 4 actions:
- Sends an Email to the person filling out the form with Fabian Williams vCard
Sends a Teams Message taking the content information from the form as the message content in the Teams card
Creates a New Office 365 Contact
Creates a new contact in MailChimp and SalesForce
Public Repo: The solution you will find on GitHub
Full Solution Private Repo – For Context in the Blog Post
In this post we will cover the following topics:
- Authenticating to the Microsoft Graph
- Wiring up your Azure Function App to Work with the Microsoft Graph
- Approach taken in the Solution
- Code Walkthrough for the Contacts & Teams Implementation
- Gotchas and Issues faced
Authenticating to the Microsoft Graph
When working with Azure Functions in the context of interacting with Microsoft Graph there are a few options. As discussed in my session there are Bindings to Microsoft Graph natively in Azure Functions, however I did not use that option in my demo and this post will not cover it either. For more on that approach please visit here. At a high level, these are the supported triggers and binding that are supported.
In our approach we will be performing the following steps:
- Creating/Registering an Application the Azure Active Directory (AAD) tenant to which you will be affecting change
- Granting API Permissions to the Microsoft Graph for Contacts.ReadWrite
- Creating the Visual Studio Solution
NB: As this is functioning in the capacity of a “utility” solution I am lever aging Application permissions [the application runs as a background service or daemon without a user signed in] and not Delegated permissions [the application needs to access the AP via the signed-in users consent], this will become obvious as I employed MSGraph for the Contacts but employed Teams Webhook for the Teams Message… more to come below.
Application Registration & Permissioning
The thing to note here is that you will be registering the App utilizing the Azure Subscription associated with your Office 365 tenancy. If you have a login that is associated to many, ensure that you have switched directories to the one belong to your O365 subscription.
Once that is complete, in order to call the Microsoft Graph with an application identity permission, you will need to register the App in AAD. Begin by clicking “Azure Active Directory” in the Azure Portal.
Create a new App being mindful to capture the Application ID, Application Secret, Tenant ID, Redirect URL, and Domain, we will use those later and they are called out in #1 and #2 below.
In call out #1 we can either use Certificate or Client Secrets, in a previous post I go into using Certificates when using CSOM to provision SharePoint Webs and Reading files in OneDrive so in this example I will be using Client Secrets. Create yourself a new Client Secret by providing it a description as well as setting the expiry year.
The next important measure is to ensure that you (1) Select the appropriate permissions you need for the task you need to peform as well as (2) Grant ‘yes grant’ the Permissions as well. Before you ask, yes it is possible to assign the permissions but not grant them 🙂
Note that under Type you see “Appliation” for the Contacts.ReadWrite as opposed to Delegated as in the below item. This permits me to run without the end users concent by “Granting” permission to the App. Conversly as you will see below, if I wanted to send a message to a Teams Channel the option to Send is “NOT” in an Application Permission Scope it is in a Delegated as seen below
now looking under App Permission
Far easier for me to do this Teams work as I will cover later using the Webhook feature in Teams and then do a HttpClient call in Azure Function.
Visual Studio Solution for Contacts in Graph
Picking up from where we covered how to create an Azure Function Solution in Visual Studio, the first piece of business is to add some NuGet packages. As we will be calling Microsoft Graph and MSAL.Net SDK libraries we will need to add the following:
With that bit out of the way, I will be the first to say to you that if this was “not” for Demoware, I would do my credential in KeyVault, but this poor mans apparoach still works as it does not store the file or inforamation in code rather I have a file that is pushed up to my Azure Functions App which behind the scene may be accessed as below:
This static function is called to set a config variable which will be passed as a parameter to GraphServiceClient [screenshot further below] and please reference the Github Repo for the actual code.
Note these are the infomation I cited earlier that you would need to capture and remember. Note that I am looking for a file which you saw earlier in my Visual Studio solution called “certappsettings.json” under the root folder.Once the Azure Functions is published, this file will be hosted in that location as seen below, the contents of which houses the information captured.
Next we use the IAuthenticationProvider interface from the Microsoft.Graph namespace to create a static function to handle the actual authentication for us. This too will be called from or Azure Function method and for completness may abe found in the Github Repo.
Once these helper funtions are defined and squared away we can now code the Azure Function that will be responsible for creating the actual Contact in Office 365 beginning on line 26 here and screen shot below.
In the end you will have a new contact created based on the payload sent to the Azure Function from the invocation of the submit button on the anonymous Microsoft Form.
Microsoft Teams Message Creation
As we saw above, if my intent is to use this as a “utility” solution and not employing any interaction from an end user, then I will need to be creative. I opted for a solution that already existed in Microsoft Teams known as Webhooks. They work surprisingly simple and can be called from a variety of services. In my case I will be making an HttpClient Call with a POST method. Configuration of the webhook is not onerous and instructions may be found here.
Once the Webhook was configured, its just a matter of taking the same payload from the anonymous Form and passing it along in the message body. The below screenshot code may be found here. You will see that the webhook URI endpoint is called out on Line 23 as an environment variable element tucked away in the local.appsettings.json file which as we covered in the session will need to be propogated to your Azure Functions as well, or better yet kept in Azure Keyvault.
Note that in this function we are using a Queue trigger as opposed to the HTTP trigger in the initial MS Forms invocation. Also recall that now that we have Durable Functions to do this kind of Function chaining that as in this case starts with one singlular payload that can be paralled tasked and the outcome monitored. Once this functions runs you will get an output as seen below in Teams.
So, I sincerley hope that you enjoyed the session and this accompaniment gave you good context for trying this out on your own. Please leave me comments/questions if you have any. Cheers