Post GitHub Events To A Microsoft Teams Channel Using C#.NET

Webhooks allow you to build or set up integrations that subscribe you to events on GitHub.com. We will use the webhook to get notified of events on our custom web API endpoint and will use the attributes from the payload received to POST to a team's channel using Microsoft Teams incoming webhook. Developers can proactively get notified on a team's channel they are collaborating on. For the purpose of this article, we will just focus on push events for a particular repository. You can extend it to events outside of a repository as well.
 
Let us get started!
 
Here are our main steps,
  • Configure Microsoft Teams incoming webhook.
  • Develop Web API endpoint for receiving events from GitHub.
  • Configure GitHub repository webhook.

Configure Microsoft Teams incoming webhook

 
If you have not configured an incoming webhook for a Microsoft Teams Channel, please follow the instructions below. If you have an incoming webhook configured already, please have the URL to the webhook handy. This will be needed for our next step.
 
Right-click the channel of interest in Microsoft Teams and choose Connectors,
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Select Configure option for Incoming Webhook,
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Name your incoming webhook and upload an image of your choice. This image will be displayed as part of your webhook messaging. Choosing a GitHub image will be ideal.
 
That way developers can easily see the source of the notification as GitHub. This will also be very helpful if you have other webhooks in the channel for other notifications and if you want to differentiate GitHub from others just at a quick glance. 
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
After you gave it a good name and optionally uploaded an image of choice, click on Create.
 
Copy the URL for the incoming webhook and keep it handy. You will need this for our next step.
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 

Develop Web API endpoint for receiving events from GitHub 

 
We will create a REST endpoint in C# to receive the push event from GitHub. After we create the API we will configure it in GitHub so that we receive the payload from GitHub for the push event. When GitHub notifies you, the payload in JSON string format has a lot of attributes as shown in the image below,
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
For the purpose of this article, we will only use a few objects and attributes in the JSON structure. We will use the following attributes,
  • ref (root object)
  • name (repository object)
  • the message, timestamp, URL, committer (commits object)
  • name, email, username (commits==>committer object)
These attributes are a good start and help developers get a basic view into the push event all without leaving the MS Teams channel. For this example, we will also deep-link to the commit using the URL attribute of the commits object, in case we need to find details. We will deserialize the payload to the basic attributes that are needed and then POST it to MS Teams channel as an adaptive card. Adaptive Cards are platform-agnostic snippets of UI, authored in JSON, that apps and services can openly exchange.
 
Please refer to Adaptive Cards if you are interested to learn more about it.
 
Let us get going with our WebAPI project. We will use Visual Studio and create an ASP.NET Core Web API project.
  • Open Visual Studio and create an ASP.NET Core Web API project using C#,
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Configure your new project.
 
Give it a good name and click Next.
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
We will pick .NET 5.0 for the Target Framework in the Additional information form. You can pick a framework of your choice. .NET 5.0 has some great features out of the box including Swagger support. Click Create after you made your selection,
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
After the solution gets loaded, let us create the necessary classes for our WebAPI. Let us create our controller class first. Right-click the Controllers folder and add a new controller,
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Give it a good name and click Add,
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Let us create the necessary classes for our GitHub and Teams objects. We will put both of them under the Models folder. Right-click the project and create a new folder Models,
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Now right-click the Models folder and create a class for our GitHub which we will call GithubCommit,
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Let us also create a new class for our Teams which we will call TeamsMessage,
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
With all the class files in place, let us get to some coding.
 
First, we will create the necessary attributes for our GitHub payload that we can deserialize. We are only interested in a subset of attributes coming in from the payload.
 
GithubCommit.cs
  1. public class GithubCommit {  
  2.     [JsonProperty(PropertyName = "ref")]  
  3.     public string BranchReference {  
  4.         get;  
  5.         set;  
  6.     }  
  7.     public Repository Repository {  
  8.         get;  
  9.         set;  
  10.     }  
  11.     public Commits[] Commits {  
  12.         get;  
  13.         set;  
  14.     }  
  15. }  
  16. public class Commits {  
  17.     [JsonProperty(PropertyName = "message")]  
  18.     public string Message {  
  19.         get;  
  20.         set;  
  21.     }  
  22.     [JsonProperty(PropertyName = "timestamp")]  
  23.     public DateTime TimeStamp {  
  24.         get;  
  25.         set;  
  26.     }  
  27.     [JsonProperty(PropertyName = "url")]  
  28.     public string URL {  
  29.         get;  
  30.         set;  
  31.     }  
  32.     [JsonProperty(PropertyName = "committer")]  
  33.     public Committer Committer {  
  34.         get;  
  35.         set;  
  36.     }  
  37. }  
  38. public class Committer {  
  39.     [JsonProperty(PropertyName = "name")]  
  40.     public string Name {  
  41.         get;  
  42.         set;  
  43.     }  
  44.     [JsonProperty(PropertyName = "email")]  
  45.     public string Email {  
  46.         get;  
  47.         set;  
  48.     }  
  49.     [JsonProperty(PropertyName = "username")]  
  50.     public string Username {  
  51.         get;  
  52.         set;  
  53.     }  
  54. }  
  55. public class Repository {  
  56.     [JsonProperty(PropertyName = "name")]  
  57.     public string RepoName {  
  58.         get;  
  59.         set;  
  60.     }  
  61. }   
Next, we will create the necessary class for our teams message. Please note that Teams support adaptive cards and some of the properties are centric around the branding of the card.
 
TeamsMessage.cs
  1. public class TeamsMessage {  
  2.     [JsonProperty(PropertyName = "type")]  
  3.     public string Type {  
  4.         get;  
  5.         set;  
  6.     }  
  7.     [JsonProperty(PropertyName = "themeColor")]  
  8.     public string ThemeColor {  
  9.         get;  
  10.         set;  
  11.     }  
  12.     [JsonProperty(PropertyName = "summary")]  
  13.     public string Summary {  
  14.         get;  
  15.         set;  
  16.     }  
  17.     [JsonProperty(PropertyName = "sections")]  
  18.     public Sections[] Sections {  
  19.         get;  
  20.         set;  
  21.     }  
  22. }  
  23. public class Sections {  
  24.     [JsonProperty(PropertyName = "activityTitle")]  
  25.     public string ActivityTitle {  
  26.         get;  
  27.         set;  
  28.     }  
  29.     [JsonProperty(PropertyName = "activitySubtitle")]  
  30.     public string ActivitySubtitle {  
  31.         get;  
  32.         set;  
  33.     }  
  34.     [JsonProperty(PropertyName = "activityImage")]  
  35.     public string ActivityImage {  
  36.         get;  
  37.         set;  
  38.     }  
  39.     [JsonProperty(PropertyName = "markdown")]  
  40.     public bool Markdown {  
  41.         get;  
  42.         set;  
  43.     }  
  44. }   
Let us make sure that our Teams webhook is a configurable entry in our configuration file (appsettings.json). Please replace the Repository key value with the name of the GitHub repository, TeamsURL with the URL of the webhook that you configured in the first step.
 
You can also put a pretty picture that goes along with the card for our team's message. Please replace the GithubImage value with a URL to a nice image that will be displayed in our team's message card.
 
Here is a quick snapshot of our appsettings.json file. 
 
appsettings.json
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Now with both of our classes required for deserializing the payload coming from GitHub and serializing the object for our team's card message, let us move onto our API endpoint logic. Let us take advantage of dependency injection and inject the configuration object into the constructor so that we can call our configurable entries in appsettings.json,
 
NotifyController.cs
  1. public class NotifyController: ControllerBase {  
  2.         private readonly IConfiguration _config;  
  3.         public NotifyController(IConfiguration config) {  
  4.             _config = config;  
  5.         }   
Now for our main POST endpoint.
 
NotifyController.cs
  1. // POST api/<NotifyController>    
  2. [HttpPost]  
  3. public async Task < IActionResult > Post() {  
  4.     using(StreamReader reader = new(Request.Body, Encoding.UTF8)) {  
  5.         var resultsData = await reader.ReadToEndAsync();  
  6.         GithubCommit githubCommitObject = null;  
  7.         try {  
  8.             githubCommitObject = JsonConvert.DeserializeObject < GithubCommit > (resultsData);  
  9.             var gitRepoName = githubCommitObject.Repository.RepoName;  
  10.             var repoName = _config["GithubEvents:Repository"].ToString().Trim().ToLower();  
  11.             if (repoName.ToLower() == repoName.ToLower()) {  
  12.                 await PostToTeamsChannel(_config["GithubEvents:TeamsURL"].ToString().Trim(), repoName, githubCommitObject.BranchReference, githubCommitObject.Commits[0].Committer.Name, githubCommitObject.Commits[0].Message, githubCommitObject.Commits[0].URL, _config["GithubEvents:GithubImage"].ToString().Trim());  
  13.             }  
  14.         } catch (Exception ex) {  
  15.             //Eating the exception. Instead notify/log.    
  16.             string exception = ex.Message;  
  17.         }  
  18.     }  
  19.     return Ok();  
  20. }   
The logic is simple enough. We read the payload from the body received from the GitHub event, deserialize it as a GithubCommit object and check if the repository name matches the repository that is of interest and if it matches, post it to our team's channel.
 
Let us explore PostToTeamsChannel method next.
 
NotifyController.cs
  1. private static async Task < String > PostToTeamsChannel(string teamsURL, string repoName, string branchReference, string author, string commitMessage, string commitURL, string teamsPostImage) {  
  2.     string success = "false";  
  3.     if (teamsURL.Trim().Length > 0) {  
  4.         using  
  5.         var client = new HttpClient();  
  6.         TeamsMessage teamsMessage = new() {  
  7.             Type = "MessageCard",  
  8.                 ThemeColor = "0076D7",  
  9.                 Summary = commitMessage  
  10.         };  
  11.         Sections sections = new() {  
  12.             ActivityTitle = commitMessage,  
  13.                 ActivitySubtitle = string.Format("Author: {1}, On {3} branch: {2} [Commit]({0}) ", commitURL, author, branchReference, repoName),  
  14.                 ActivityImage = teamsPostImage,  
  15.                 Markdown = true  
  16.         };  
  17.         teamsMessage.Sections = new Sections[] {  
  18.             sections  
  19.         };  
  20.         var teamsPayload = JsonConvert.SerializeObject(teamsMessage);  
  21.         var response = await client.PostAsync(teamsURL, new StringContent(teamsPayload, Encoding.UTF8, "application/json"));  
  22.         var contents = await response.Content.ReadAsStringAsync();  
  23.         if (response.IsSuccessStatusCode) {  
  24.             success = "true";  
  25.         }  
  26.     }  
  27.     return success;  
  28.    }  
  29. }  
The method is also simple enough. It formats the attributes necessary for our card in a JSON adaptive card format. If necessary, you can template these cards to make them more generic. But for the purpose of this article, we will keep it simple. Please note, one of the attributes in the card is a deep link into GitHub commit URL.
 
Now we will have to host our POST endpoint in a publicly accessible way so that GitHub can send events to our endpoint. Please proceed with hosting the WebAPI endpoint. Hosting a web app is outside the scope of this article. Please have the endpoint URL handy which we will need to configure in GitHub repository settings. 
 
Not let us proceed with our final step of configuring the webhook in GitHub. 
 

Configure GitHub repository webhook

 
Log in to your GitHub account and select the repository that you are interested in getting notified on and then click on Settings,
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Click Webhooks in the left navigation pane.
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Specify our API endpoint URL for Payload URL, change the Content-type to application/JSON and click Add webhook. You can leave the rest of the fields with default settings.
 
Note
You can set a secret code if you prefer, this will make sure that you have the security in place to validate that the event is coming from GitHub. You need to have the logic to read the additional security attributes inside our POST call if you need to make it more secure. For this example, we will keep this simple and will leave the Secret field empty.
 
Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
That is it! The next time you complete a push to the repository, GitHub will notify us on our POST endpoint with a payload and our logic will in turn process the payload and post some of the attributes from the payload as an adaptive card to the team's channel.
 
We have completed the basic necessary steps and coding for pro-actively notifying a GitHub event in a Microsoft Teams channel using C#.
 
Here is a sample message card that got posted to one of my Microsoft Teams Channel.

Post GitHub Events to a Microsoft Teams Channel Using C#.NET
 
Happy coding and happy collaborating!!!