Create a Custom Channel and Group Tab with ASP.NET Core MVC

In this quickstart we'll walk-through creating a custom channel/group tab with C# and ASP.Net Core MVC. We'll also use App Studio for Microsoft Teams to finalize your app manifest and deploy your tab to Teams.


  • To complete this quickstart you'll need a Microsoft 365 tenant and a team configured with Allow uploading custom apps enabled. To learn more, see Prepare your Microsoft 365 tenant.

    • If you don't currently have a Microsoft 365 account, you can sign up for a free subscription through the Microsoft Developer Program. The subscription will remain active as long as you're using it for ongoing development.
  • You'll use App Studio to import your application to Teams. To install App Studio select Apps Store App at the bottom-left corner of the Teams app, and search for App Studio. Once you find the tile, select it and choose install in the pop-up window dialog box.

In addition, this project requires that you have the following installed in your development environment:

  • The current version the Visual Studio IDE with the .NET CORE cross-platform development workload installed. If you don't already have Visual Studio, you can download and install the latest Microsoft Visual Studio Community version for free.

  • The ngrok reverse proxy tool. You'll use ngrok to create a tunnel to your locally running web server's publicly-available HTTPS endpoints. You can download it here.

Get the source code

Open a command prompt and create a new directory for your tab project. We have provided a simple Channel Group Tab project to get you started. To retrieve the source code you can download the zip folder and extract the files or clone the sample repository into your new directory:

git clone

Once you have the source code, open Visual Studio and select Open a project or solution. Navigate to the tab application directory and open ChannelGroupTabMVC.sln.

To build and run your application press F5 or choose Start Debugging from the Debug menu. In a browser, navigate to the URLs below and verify that the application loaded properly:

  • http://localhost:44360
  • http://localhost:44360/privacy
  • http://localhost:44360/tou

Review the source code


This project was created from an ASP.NET Core 2.2 Web Application empty template with the Advanced - Configure for HTTPS check box selected at setup. The MVC services are registered by the dependency injection framework's ConfigureServices() method. Additionally, the empty template doesn't enable serving static content by default, so the static files middleware is added to the Configure() method:

public void ConfigureServices(IServiceCollection services)
public void Configure(IApplicationBuilder app)

wwwroot folder

In ASP.NET Core, the web root folder is where the application looks for static files.

AppManifest folder

This folder contains the following required app package files:

  • A full color icon measuring 192 x 192 pixels.
  • A transparent outline icon measuring 32 x 32 pixels.
  • A manifest.json file that specifies the attributes of your app.

These files need to be zipped in an app package for use in uploading your tab to Teams.


In the Visual Studio Solution Explorer window right-click on the project and select Edit Project File. At the bottom of the file you'll see the code that creates and updates your zip folder when the application builds:

    <PostBuildEvent>powershell.exe Compress-Archive -Path \"$(ProjectDir)AppManifest\*\" -DestinationPath \"$(TargetDir)\" -Force</PostBuildEvent>

    <EmbeddedResource Include="AppManifest\icon-outline.png">
    <EmbeddedResource Include="AppManifest\icon-color.png">
    <EmbeddedResource Include="AppManifest\manifest.json">


ChannelGroup.cs presents a Message object and methods that will be called from the Controllers during configuration.



ASP.NET Core treats files called Index as the default/home page for the site. When your browser URL points to the root of the site, Index.cshtml will be displayed as the home page for your application.


The partial view markup _Layout.cshtml contains the application's overall page structure and shared visual elements. It will also reference the Teams Library.


The controllers use the ViewBag property to transfer values dynamically to the Views.

Establish a secure tunnel to your tab

Microsoft Teams is an entirely cloud-based product and requires that your tab content be available from the cloud using HTTPS endpoints. Teams doesn't allow local hosting. You'll need to either publish your tab to a public URL, or use a proxy that will expose your local port to an internet-facing URL.

To test your tab you'll use ngrok. Your server's web endpoints will be available while ngrok is running on your local machine. If you close ngrok, the URLs will be different the next time you start it.

  • Open a command prompt in the root of your project directory and run the following command:

    ngrok http https://localhost:443560 -host-header="localhost:44360"
  • Ngrok will listen to requests from the internet and will route them to your application when it is running on port 44355. It should resemble where y8rCgT2b is replaced by your ngrok alpha-numeric HTTPS URL.

  • Be sure to keep the command prompt with ngrok running and to make note of the URL — you'll need it later.

Update your application

Within Tab.cshtml the application presents the user with two option buttons for displaying the tab with either a red or gray icon. Choosing the Select Gray or Select Red button fires saveGray() or saveRed(), respectively, sets settings.setValidityState(true), and enables the Save button on the configuration page. This code lets Teams know that you have satisfied the configuration requirements and the installation can proceed. On save, the parameters of settings.setSettings are set. Finally, saveEvent.notifySuccess() is called to indicate that the content URL has successfully resolved.


For your tab to display in Teams, you must include the Microsoft Teams JavaScript client SDK and include a call to microsoftTeams.initialize() after your page loads. This is how your tab and the Teams client communicate:

  • Navigate to the Shared folder, open _Layout.cshtml, and add the following to the <head> tag:

    <script src=""></script>
    <script src=""></script>


Don't copy/paste the <script src="..."> URLs from this page, as they may not represent the latest version. To get the latest version of the SDK, always go to: Microsoft Teams JavaScript API.


Open Tab.cshtml and update the embedded <script> as follows:

  • At the top of the script, call microsoftTeams.initialize().

  • Update the websiteUrl and contentUrl values in each function with the HTTPS ngrok URL to your tab.

Your code should now look like the following with y8rCgT2b replaced with your ngrok URL:


    let saveGray = () => {
        microsoftTeams.settings.registerOnSaveHandler(function (saveEvent) {
                websiteUrl: ``,
                contentUrl: ``,
                entityId: "grayIconTab",
                suggestedDisplayName: "MyNewTab"

    let saveRed = () => {
        microsoftTeams.settings.registerOnSaveHandler(function (saveEvent) {
                websiteUrl: ``,
                contentUrl: ``,
                entityId: "redIconTab",
                suggestedDisplayName: "MyNewTab"

Make sure to save the updated Tab.cshtml.

Build and run your application

  • In Visual Studio press F5, or choose Start Debugging from the Debug menu. Verify that ngrok is running and working properly by opening your browser and going to your content page via the ngrok HTTPS URL that was provided in your command prompt window.


You need to have both your application in Visual Studio and ngrok running to complete this quickstart. If you need to stop running your application in Visual Studio to work on it keep ngrok running. It will continue to listen and will resume routing your application's request when it restarts in Visual Studio. If you have to restart the ngrok service it will return a new URL and you'll have to update your application with the new URL.

Upload your tab to Teams


We use App Studio to edit your manifest.json file and upload the completed package to Teams. You can also manually edit the manifest.json file if you prefer. If you do, be sure to build the solution again to create the file to upload.

  • Open the Microsoft Teams client. If you use the web based version you can inspect your front-end code using your browser's developer tools.

  • Open App studio and select the Manifest editor tab.

  • Select the Import an existing app tile in the Manifest editor to begin updating the app package for your tab. The source code comes with its own partially complete manifest. The name of your app package is It should be found here:

  • Upload to App Studio.

Update your app package with Manifest editor

Once you've uploaded your app package into App Studio, you'll need to finish configuring it.

  • Select the tile for your newly imported tab in the right panel of the Manifest editor welcome page.

There's a list of steps in the left-hand side of the Manifest editor, and on the right, a list of properties that need to have values for each of those steps. Much of the information has been provided by your manifest.json but there are a few fields that you'll need to update:

Details: App details

In the App details section:

  • Identification: select Generate to replace the placeholder id with the required GUID for your tab.

  • Developer information: update the Website URL field with your ngrok HTTPS URL.

  • App URLs: update the Privacy statement to https://<yourngrokurl>/privacy and Terms of use to https://<yourngrokurl>/tou>.

Capabilities: Tabs

In the Tabs section:

  • Team Tab: select Add.

  • In the Team tab pop-up window update the Configuration URL to https://<yourngrokurl>/tab.

  • Finally, make sure the can update configuration? Team, and Group chat boxes are checked and select Save.

Finish: Domains and permissions

In the Domains and permissions section:

  • The Domains from your tabs field should contain your ngrok URL without the HTTPS prefix - <yourngrokurl>

Finish: Test and distribute


In the Description field on the right you'll see the following warning:

⚠ "The 'validDomains' array cannot contain a tunneling site..."

This warning can be ignored while testing your tab.

In the Test and distribute section:

  • Select Install.

  • In the pop-up window's Add to a team or chat field enter your team and select Install.

  • In the next pop-up window choose the team channel where you would like the tab displayed and select Set up.

  • In the final pop-up window select a value for the tab page (either a red or gray icon) and select Save.

To view your tab, navigate to the team you installed it on, and select it from the tab bar. The page that you chose during configuration should be displayed.