Using Azure Functions to empower your Teams
In today’s world we’re receiving an enormous amount of e-mail.
A lot of the e-mail I’m receiving during the day (and night) is about errors happening in our cloud environment and sometimes someone needs to follow up on this.
At the moment this is a real pain because there’s a lot of false-positives in those e-mails due to the lack of configuration and possibilities in our monitoring software. The amount of e-mails is so painful, most of us have created email rules so these monitoring emails ‘go away’ and we only check them once per day. Not really an ideal solution.
But what if I told you all of this pain can go away with some serverless magic and the power of Microsoft Teams. Sounds great, right?
How to integrate with Microsoft Teams?
This is actually the easiest part if you’re a developer.
If you’re already running Microsoft Teams on your Office 365 tenant, you can add a channel to a team to which you belong and add a Webhook connector to it. I’ve created a channel called Alerts
on which I added an Incoming Webhook
connector.
After having saved the connector you’ll be able to copy the actual webhook URL which you need to use in order to POST messages to the channel.
In order to test this webhook, you can spin up Postman and send a POST request to the webhook URL.
The only thing you need to specify is the text
property, but in most cases adding a title
makes the message a bit prettier.
{
"title": "The blog demo",
"text": "Something has happened and I want you to know about it!"
}
When opening up the Teams you’ll see the message added to the channel.
That’s all there is to it in order to set up integration from an external system to your Team.
How will this help me?
Well, think about it. By sending a POST to a webhook, you can alert one (or more) teams inside your organization. If there’s an event which someone needs to respond to, like an Application Insights event or some business logic which is failing for a non-obvious reason, you can send this message real-time to the team responsible for the service.
Did you also know you can create so-called ‘actionable messages’ within Teams? An actionable message can be created with a couple of buttons which will invoke an URL when pressed. In Teams this looks a bit like so:
By pressing either one of those buttons a specified URL gets invoked (GET) and as you can probably imagine, those URL’s can be implemented to resolve the event automatically which has triggered the message in the first place.
A schematic view on how you can implement such a solution is shown below.
Over here you’re seeing an Event Grid, which contains events of stuff happening in your overall Azure solution. An Azure Function is subscribed to a specific topic and once it’s triggered a message is being posted on the Teams channel. This can be an actionable message or a plain message.
If it’s an actionable message, a button can be pressed which in its turn also sends a GET-request to a different Azure Function. You want this Function to be fast, so the only thing it does is validate the request and stores the message (command) on a (Service Bus) queue. A different Azure Function will be triggered, which will make sure the command will be executed properly by invoking an API/service which is responsible for ‘solving’ the issue.
Of course, you can also implement the resolving logic inside the last Azure Function, this depends a bit on your overall solution architecture and your opinion on decoupling systems.
How will my Azure Function post to Teams?
In order to send messages to Teams via an Azure Function, you will have to POST a message to a Teams webhook. This works exactly the same as making a HTTP request to any other service. An example is shown over here.
private static readonly HttpClient HttpClient = new HttpClient();
[FunctionName("InvokeTeamsHook")]
public static async Task Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "InvokeTeams")]
HttpRequestMessage req,
ILogger log)
{
var message = await req.Content.ReadAsAsync<IncomingTeamsMessage>();
var address = Environment.GetEnvironmentVariable("WebhookUrl", EnvironmentVariableTarget.Process);
var plainTeamsMessage = new PlainTeamsMessage { Title = message.Title, Text = message.Text };
var content = new StringContent(JsonConvert.SerializeObject(plainTeamsMessage), Encoding.UTF8, "application/json");
await HttpClient.PostAsync(address, content);
}
public class IncomingTeamsMessage
{
public string Title { get; set; }
public string Text { get; set; }
}
private class PlainTeamsMessage
{
public string Title { get; set; }
public string Text { get; set; }
}
This sample is creating a ‘plain’ message in Teams. When POSTing a piece of JSON in the IncomingTeamsMessage
format to the Azure Function, for example, the following.
{
"title": "My title in Teams",
"text": "The message which is being posted."
}
It will show up as the following message within Teams.
Of course, this is a rather simple example. You can extend this by also creating actionable messages. In such a case, you need to extend the model with the appropriate properties and POST it in the same way to Teams.
Even though Teams isn’t something I develop a lot for (read: never), I will spend the upcoming weeks investigating on how to update our DevOps work to the 21st century. By leveraging the power of Teams I’m pretty sure a lot of ‘manual’ operations can be made easier, if not automated completely.