In my latest post, I’ve shown you how you can use Azure Functions in your Microsoft Teams flow to handle errors in your environment. This stuff works great in a couple of projects I’ve worked on, but what would be even more awesome is to reply to a message in Teams when an action has completed after a button is pressed.

Well, replying & modifying the original message with a status update is quite possible and I’ll show you how in this post.

How do I send a reply to Microsoft Teams?

In the image below you can see a message having posted on my Teams channel and a reply is posted.

reply on teams message

This reply has been sent from my Azure Function. If you want to do this, you need to send a `HttpResponseMessage` with a status code 200 and a specific header value. This header value is `CARD-ACTION-STATUS` and the value will be the message which you will see in the reply.

The code for this will look something similar to the following.

public static async Task<HttpResponseMessage> Run(
	[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
	ILogger log)
{
	// Do your stuff...

	var result = new HttpResponseMessage
	{
		Headers =
		{
			{ "CARD-ACTION-STATUS", $"Timeout of `{request.Timeout}` miliseconds has expired."},
		},
		StatusCode = HttpStatusCode.OK
	};


	return result;
}

That’s all there is to it in order to send a single reply to your message.

So you also mentioned updating the original message?

Yeah, I did!

From your Azure Function (or any other API) it’s possible to change the original message. Updating the message might make sense in a couple of scenarios. The one scenario where we’re using it for is to remove the button(s) in the message, therefore limiting the ‘action’ only to a single use.

While our services are set up to be idempotent, we don’t want to spam the API with useless requests, so removing the button makes sense in our case.

In order to do this, you need to add another header to your response message, named `CARD-UPDATE-IN-BODY` and set the value to `true`. This tells the client (Teams) there’s an update for the card in the body of the response message.

If you want to use this, it makes sense to create a new card with data that’s useful after an action has been executed. The eventual code will look pretty similar to the following snippet.

public static async Task<HttpResponseMessage> Run(
	[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
	ILogger log)
{
	// Do all of your stuff...

	var result = new HttpResponseMessage
	{
		Content = new StringContent(GetContent(request.Timeout)),
		Headers =
		{
			{ "CARD-ACTION-STATUS", $"Timeout of `{request.Timeout}` miliseconds has expired."},
			{ "CARD-UPDATE-IN-BODY", "true" }
		},
		StatusCode = HttpStatusCode.OK
	};
	result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");

	return result;
}

Over here I’m creating a new `Content` property with the update of the card. I do have to make clear it’s a full replacement of the original message. Therefore, you have to create a completely new MessageCard. For me, the content of the new MessageCard looks pretty much like the following piece of JSON.

{
	"@type": "MessageCard",
	"@context": "https://schema.org/extensions",
	"summary": "Testing the timeout",
	"themeColor": "0078D7",
	"sections": [
		{
			"activityImage": "https://jan-v.nl/Media/logo.png",
			"activityTitle": "Timeout test",
			"activitySubtitle":"Testing, testing...",
			"facts": [
				{
					"name": "Timeout (miliseconds):",
					"value": "1000"
				}
			],
			"text": "The response has returned with a timeout of 1000 miliseconds.",
		}
	]
}

In Microsoft Teams this will appear like the following screenshot.

updated message and response

The message gets an `Updated` status, which makes it clear for all users this isn’t the original message.

Erroneous statements on other sites / posts

So if you stumbled on this post while searching for this functionality in a search machine, you probably know it’s hard to find anything useful on the matter. While doing research on this I also saw a post stating the response message has to be returned within 5 seconds in order for Microsoft Teams to process it and show the reply and/or updated message in the channel.
From my experience, I can tell you this isn’t true (at the moment). I’ve tested this timeout function with delays up to 30 seconds and the functionality still works properly as you can see on the image below.

response with 30 seconds

Closing up

If you want to evaluate the complete code there’s a GitHub repository called ServerlessDevOps where I’m doing all of the code updates and trying out new stuff & integrations with Microsoft Teams and Azure Functions.

So, is this something you might consider using in your own projects and keeping your DevOps workplace happy? I’d love to hear it and if you’re missing something which you want to be highlighted in future posts.

So, a couple of weeks back I wrote about leveraging the power of Logic Apps to retrieve Alerts from within your Azure ecosystem and send them to Microsoft Teams. This works great and a fellow Azure MVP, Tom Kerkhove, has enhanced the Logic Apps Template when handling Azure Monitor events.

I'm starting to become a pretty big van of Logic Apps, but there are some (obvious) downsides to it.
First, they live inside your Azure Portal. You can create, modify and export them from within the Portal, which is great, unless you want to integrate them in your ‘regular’ development cycle.

The export feature enables you to copy/paste the Logic Apps to your ARM templates, but this is suboptimal in my opinion. There’s also the Azure Logic Apps Tools for Visual Studio extension, which makes the integration a bit better, but it still feels a bit quirky.

Another downside is the 'language'. When exporting a Logic App you'll be seeing a lot of JSON. While there might be a good reason for this, it's not something I like working in and create (complex?) workflows.

If you can overcome, or accept, these downsides I'd really advice you to look into Logic Apps. If not, well read on!

Azure Functions to the rescue

If your IT organization consists of mostly developers it might make more sense to use Azure Functions to glue different systems with each other instead of Logic Apps. The biggest downside of Azure Functions in this scenario is, you don't have all of the building blocks from a Logic App to your availability. You have to create your own logic for this.

However, the major benefit of using Azure Functions as the glue to your solution is they are written in the language of your choice and can be deployed via your 'normal' CI/CD process.

The only thing the Logic App in the previous post did was receive a HTTP POST message, parsing it and send a message to Teams. All of this can also be done via a standard HTTP triggered Azure Function. And because I prefer writing C# code instead of dragging-dropping building blocks (or write JSON if you’re really hardcore), the Azure Functions approach works best for me.

How to start with this?

The first thing you need to do, besides creating an HTTP triggered Azure Function, is to deserialize the incoming message from Azure Monitor.
The easiest way to get the complete Alert object is by copying the complete JSON message and use the `Paste JSON As Classes` option in Visual Studio.

image

This will create a model with all of the properties and complex types which are available in alert. At the moment it will look very similar to the following model.

/// <summary>
/// Generated via `Paste JSON as Classes`
/// </summary>
public class IncomingAzureMonitorCommonAlertSchema
{
    public string schemaId { get; set; }
    public Data data { get; set; }
}

public class Data
{
    public Essentials essentials { get; set; }
    public Alertcontext alertContext { get; set; }
}

public class Essentials
{
    public string alertId { get; set; }
    public string alertRule { get; set; }
    public string severity { get; set; }
    public string signalType { get; set; }
    public string monitorCondition { get; set; }
    public string monitoringService { get; set; }
    public string[] alertTargetIDs { get; set; }
    public string originAlertId { get; set; }
    public DateTime firedDateTime { get; set; }
    public string description { get; set; }
    public string essentialsVersion { get; set; }
    public string alertContextVersion { get; set; }
}

public class Alertcontext
{
    public object properties { get; set; }
    public string conditionType { get; set; }
    public Condition condition { get; set; }
}

public class Condition
{
    public string windowSize { get; set; }
    public Allof[] allOf { get; set; }
    public DateTime windowStartTime { get; set; }
    public DateTime windowEndTime { get; set; }
}

public class Allof
{
    public string metricName { get; set; }
    public string metricNamespace { get; set; }
    public string _operator { get; set; }
    public string threshold { get; set; }
    public string timeAggregation { get; set; }
    public Dimension[] dimensions { get; set; }
    public float metricValue { get; set; }
}

public class Dimension
{
    public string name { get; set; }
    public string value { get; set; }
}

Once you have this model, you can deserialize the incoming alert message and start creating a message for Teams.

So, what do I send?

You’re quite restricted in what you can send to a Microsoft Teams channel via a webhook. When searching for this you’ll quickly find the different Adaptive Cards. These look nice and possibilities are also great. However, you can’t use them via a webhook. Adaptive Cards only work when using a Bot, something I really don’t want to do/configure at the moment.

The only cards which are supported in Teams, which you can send directly via a webhook, are the legacy Message Cards. While these work fine, I do hope the support for Adaptive Cards will be added soon.

What I did in the previous post was sending out a message with only a `title` and a `text` property in a JSON object. This works and might be useful in a couple scenario’s, but most of the time you want to do more as only informing the users. When an alert pops up, someone probably has to do something with the failing (?) resource.
If this ‘action’ can be automated some way, you can add a button to your message which is able to invoke some HTTP endpoint. This is great, because now we can configure an Azure Functions, Logic App, Automation Job, App Service, etc. to be the endpoint which fixes the root cause of the alert. You just have to remember Microsoft Teams has to be able to invoke the endpoint, which means it has to be a public available endpoint.
In order to add buttons to your Message Card, you have to add Actions to your message. What I came up with is the following type of message.

{
    "@type": "MessageCard",
    "@context": "https://schema.org/extensions",
    "summary": "More as 100 messages on queues",
    "themeColor": "0078D7",
    "sections": [
        {
            "activityImage": "https://jan-v.nl/Media/logo.png",
            "activityTitle": "More as 100 messages on queues",
            "activitySubtitle": "05/02/2019 19:32:20",
            "facts": [
                {
                    "name": "Severity:",
                    "value": "Sev3"
                },
                {
                    "name": "Resource Id:",
                    "value": "3b3729b4-022a-48b5-a2eb-48be0c7e7f44:functionbindings"
                },
                {
                    "name": "Entity:",
                    "value": "correct-implementation-netframework"
                },
                {
                    "name": "Metric value:",
                    "value": "10000"
                }
            ],
            "text": "There are a lot of messages waiting on the queue, please check this ASAP!",
            "potentialAction": [
                {
                    "@type": "HttpPOST",
                    "name": "Fix the stuck Service Bus",
                    "target": "https://serverlessdevops.azurewebsites.net/api/FixFailingServicebus?code=WVq4Ta3ba0i53a3qzHbLWHLnCiRNA8UnhHICIl1UfURskh/Cx0J8IQ==",
                    "body": "{\"ResourceId\": \"3b3729b4-022a-48b5-a2eb-48be0c7e7f44:functionbindings\",\"Entity\": \"correct-implementation-netframework\" }"
                }
            ]
        }
    ]
}

This defines a Message Card which looks like this inside Microsoft Teams.

image

As you can see there’s a big button in the card which enables me to do something. You can add multiple buttons over here. Aside from a fix-button I also add a button with a deeplink to the resource in the Azure Portal most of the time.

You have to keep in mind though, the only type of HTTP methods you can do are GET and POST. When making a POST request a body can be added by adding the optional `body` property to the message.

The JSON sent over here looks a bit more advanced, but as you can see, the message is also a lot more useful.

Looking great so far, can we do more?

Yes we can!

I’ll be writing some more on what you can do with Azure Functions and Microsoft Teams in a couple of my next posts. I think this integration can really help a lot of DevOps teams in keeping their environments in a healthy state, so I’m keen on sharing my experiences with it. If you can’t wait for the blogposts to appear, you can also follow along the progress in my Serverless DevOps repository on GitHub. If you take a look over there, you can see what I’m doing in order to send and receive messages in Teams & Azure Functions.

Stuff I like from this year’s Build conference

.NET Core 3 Preview 4 can be downloaded right now. This new preview brings the Chart control to .NET Core & some WPF improvements. What I like most is the versioning change and the Tiered Compilation. I’m still reading up on this second thing, but it sounds awesome a major reason to upgrade to the latest & greatest! Some more information on TC can be found on a Microsoft blog post dedicated to it: https://devblogs.microsoft.com/dotnet/tiered-compilation-preview-in-net-core-2-1/
The Docker improvements are nice also, but I’m not using it a lot these days so don’t have much of an opinion on these things.

Something which struck me as odd is the announcement of .NET 5, which is .NET Core vNext. The explanation of this version number clears things up a bit though.

We’re skipping the version 4 because it would confuse users that are familiar with the .NET Framework, which has been using the 4.x series for a long time. Additionally, we wanted to clearly communicate that .NET 5 is the future for the .NET platform.

From what I gather from this we can all (.NET Framework and .NET Core) to .NET 5 without much hassle. I don’t know if this is true, but it would make sense from my perspective.

Another announcement was the integration of GitHub and Azure DevOps, which is great! Where Azure DevOps shines at being a great enterprise/company working environment, GitHub shines in collaboration with external people. With this integration, we’ll be able to leverage the power of both platforms where needed more easily. Also, signing in with your GitHub account on Azure DevOps or the Azure Portal is big! You can now add your GitHub identity to the Azure Active Directory and be done with it. Awesome!

The same post mentions being able to do deployment pipelines via YAML now. It’s called Unified Pipelines, which is a great improvement!
By chance we were also looking to Azure Artifacts at the project I’m working on now and with the announcement of yesterday this seems appears like a no-brainer now as the service is now included in the Basic license!

Then there’s the Kubernetes news, which. is. the. best!
I’ve never felt much for the container ecosystem. I do understand what it does and how it’s an improvement to IaaS, but I live mostly in a PaaS, FaaS and SaaS environment, so moving back to ‘the virtual metal’ feels like a step back.
But, the serverless Kubernetes and Kubernetes-based Event-driven Autoscaling (KEDA) is amazing! While it might not be fully serverless, it’s still something which can bring a lot of value to our customers and if we’re honest, that’s what matters the most. I do wonder if this will also become available on theOpenShift platformas KEDA is a partnering between Microsoft & Red Hat. KEDA will also be available on the OpenShift platform!
It’s also open source and can be found on GitHub: https://github.com/kedacore/keda

Are you using Windows Subsystem for Linux? Well, version 2 is announced also, which is even better! It’s faster, has more system calls available and Docker images run right away!
Something which goes hand in hand with the WSL is the command-line terminal and it has had some major improvement! Scott Hanselman has written a nice post on it and how you can tune the terminal. While I was just getting used to ConEmu, I think I’ll just use the new Terminal experience right from the start.

There were also a lot of announcements on machine learning, blockchain, artificial intelligence, mixed reality, etc. While all of this sounds great, it’s not stuff I work with on a daily basis. If you’re interested in this stuff, I’d advise you to check out all of the news posts on these other subjects.
I’ll be sure to check out KEDA once I get around to it, it’s just too awesome not to play with it.

Update

While scrolling through my Twitter feed today I saw a lot of other stuff which peeked my interest.

Apparently dependency injection in Azure Functions is a thing now, for quite some while. I probably missed this announcement in March, as the documentation dates from a couple of months ago. Still, very useful!

The Durable Functions also have gotten quite a bit of love for stateful actor-like capabilities. While I haven’t worked with the Actor model (yet), it is something I would love to dig into. With this announcement working with the Actor model will be even more awesome!
And of course, the API Management integration of Azure Functions is great! There already was some basic Proxy functionality in Azure Functions, but with the full integration of APIM this will work even better!

For App Services we now have a Free Linux tier. Even though I don’t do a lot of development which will be published to a Linux App Service, I do recognize this is a great improvement for a lot of projects. Connecting to a vNet is now also supported for Linux App Services, which is great if you’re working in a hybrid scenario, or have some ‘secured’ resources somewhere.
From the UX improvements it also looks like Docker integration can be found everywhere nowadays. So if you haven’t looked into containers & Docker yet, now is a time to do so. It’ll become very important for us developers to at least know the basics off of it.

Let’s not forget one major improvement in the security space. We now have support for passwords with a length of 256 characters! Finally!

Update 2

It appears the full Entity Framework will become available to .NET Core 3.0! This is major, because the full Entity Framework has a lot more capabilities compared to the Entity Framework Core version. People still stuck on the .NET Framework because of EF should now be able to upgrade. Still, the packages are in preview, so don’t migrate just yet.

Something I like very much is the enhanced syntax highlighting for ARM templates in VS Code. Also, the enhanced schema ‘intellisense’ is very useful when working with these large JSON files.

Have you also noticed the improved Azure Portal? Lots of small improvements which makes the navigation in the portal a lot more slick. Especially the improved resource graphs are useful. Now I don’t have to create my own dashboards in PowerBI or something like it anymore.

With the announced GitHub integration, we also get Azure Boards integration to GitHub. This will make managing your code & project a lot easier when working with both systems on a single project.

And last, but certainly not least, the React Native for Windows repository. Not sure if this was announced at //build/, but I saw it appear in my timeline and it’s awesome enough to mention over here. Now you can create a React Native application and deploy it as a Windows 10 application, which makes it supported for devices like PC’s, tablets, Xbox, Hololens, etc. Great stuff indeed!

I’ve written about empowering your Teams with Azure Functions a while back, but this isn’t the only way to create value. You can also use Azure Logic Apps.

Logic Apps are a way to express powerful integrations with (several different) systems in a visual workflow based way. It has a lot of similarities with other (Microsoft) workflow systems from the past, so it should strike very familiar to most (Enterprise) developers.

Being a visual workflow solution, it doesn’t warm the heart of most developers. However, the world doesn’t consist solely of developers and this solution being visual is a very big advantage if you’re not a coder or like to deliver value instead of just more code.

First step

The first step you need (or actually, WANT) to take is create a Webhook connector on a channel. You can check my previous post on how to do this.

Posting to this channel has to be done in a similar way. You will still need to post some JSON in a predefined format to this webhook.

Next step: Setting up Alerts

In order to make your DevOps process a bit easier, it’s very useful to leverage the power of Application Insights and Alerts. For this to work, you need to know what metrics you actually want to be alerted for. I’m going to assume you already have some monitoring in place with appropriate metrics. If not, you should definitely define some. They can be tuned afterward.

Adding or modifying new alerts is as easy as clicking on the `Alerts` option in your service.

clip_image001

On this blade, you’ll see an overview of all alerts which are already defined and can create new ones.

clip_image001[7]

When creating new alert rules you have to specify which signal type you want to create an alert for. At the moment there are three different types you can choose from Metrics, Log Search and Activity Log.

The other filter you can use is the Monitor Service.

If you leave both options to `All`, you’ll see all possible type of signals to create alert rules for.

clip_image001[9]

In my case, I like to receive an alert when my service plan is hitting its limits, like a high CPU, Memory usage or low response times. You can configure all of this, and more, on this page. The one on the image below shows you how to set an alert when the CPU has an average usage of at least 60%.

clip_image001[5]

By selecting the proper resource group and condition you want to get alerted for, you can specify one or more so-called Action Groups.

clip_image001[1]

A single action group is responsible for handling one specific action, like sending data to a webhook, as shown over here.

clip_image001[3]

Keep in mind though, you should NOT fill out the webhook from the Teams channel over here. Posting a message to a Teams channel requires a specific JSON message, which isn’t compatible with the JSON sent via an Alert. The webhook you want to specify over here is the location to the handler of your JSON message, like the logic app we’ll create in the next step.

Handling the Alerts

After having set up your alerts and having made sure they actually work, it’s time to handle them. In order to check if the alerts worked, I’ve lowered the thresholds a bit in order to receive alerts in an orderly fashion.

You can view which alerts have been triggered via the Alerts page in Azure Monitor.

clip_image001[7]

What we need to do now, is receive the JSON of the Alert and send it in a different format to our Teams webhook. As I already mentioned, the easiest way to do this is via Azure Logic Apps. You can even make external calls to other systems, Azure Functions, etc.

The first thing you need to do in your logic app is to specify the JSON scheme which is sent to the app. There is quite a bit of documentation available on this, but I find the easiest way is to fail fast and go from there.
What I mean with this is, create the Logic App without a good schema and save it.
By doing so you will now have the webhook address of your Logic App. You can now go back to your Alert Action Group and fill out this address in the webhook textbox.

Going back to the Logic App, you will now probably see a couple of failed events.

clip_image001[9]

If not, make sure to trigger one or two Alerts in order to get these failed events. What’s great about this is the complete context of this event is stored, including the JSON message.

clip_image001[11]

For now, the only thing you need to do is to copy the contents of the `body` element.

This content can be pasted inside your step `When a HTTP request is received` on the link `Use sample payload to generate schema`.

clip_image001[13]

This saves you from going through the docs, only to discover something is missing or something even worse. The schema of your message is now auto-created.

This enables us to create a new HTTP-step in order to POST a message to our Teams channel

image

Of course, you can make this message as fancy as you’d like, but this is about all the basics you need in order to create a basic alert on Teams.

image

This all looks very complex

Well, if you gloss over it, it might look like this. Especially if you know there are also out of the box Teams actions which you can leverage in a Logic App.

clip_image001[15]

The ‘downside’ (or maybe it’s an upside) to these actions is they need an Identity known in Teams (= your Office 365 tenant). While it’s possible to create a special identity for this, it’s not something I like much for this specific case.

One other thing, you still need to do everything yourself when using the default Teams actions. The only thing it’ll make a bit easier is POST’ing the message to Teams. While the JSON body might look a bit hard at first, it’ll grow on you and will enable you to create messages with a bit more flexibility.

But if you’re not a developer or operations person, the out of the box actions might be good enough for you.


That’s it for now. I’ll continue this series with some other posts on how to use all of this in your production environment and save you some time on repetitive operational work.

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.

image

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.

image

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

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:

image

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.


image

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.

image

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.