Adding Custom C# Slash Commands To Mattermost

The Challenge

At the beginning of the Corona pandemic, we had to quickly come up with an integration of the meeting client we had in use at the time into the Mattermost collaboration software. If you're not familiar with it - it's a team collaboration platform that's very similar to Slack but can be hosted on premise. It offers a nice way to extend its functionality using so called slash commands. You simply type a "/" and the UI offers a number of extensions that can be customized:

This article describes a way to add a custom command to this list that is then executed in C#.

Setting up the WebAPI

As a slash command basically uses a post request and expects the result to be returned in the response, the easiest way is to simply use a Web API for this purpose. In the sample code, you'll find the relevant code parts in the BlizzController.cs. First, we check for the validity of a token that is passed as a request parameter. This is a security measure to make sure the API is not misused maliciously to spam into your Mattermost channels.

The code then makes use of Lorenzo Polidori's HTTP content parser in order to parse the request's body. The syntax of the body is documented here - for the simple sample command we just consume the "text" part of the request and reformat it in a way that allows to open a meeting by clicking on the link rendered in Mattermost. This link is then decorated with the name of the user typing the command.

[HttpPost]
public IActionResult Post()
{
    // parse the request body
    HttpContentParser parser = new HttpContentParser(Request.Body);
    Task.Run(() => parser.Parse()).Wait();
    if (parser.Success)
    {
        // check for correct token to make sure this is a valid request
        if (parser.Parameters["token"] != "c4fdge3d7iyj88xaxoa7uyxy6o")
        {
            return BadRequest();
        }

        SlashCommandResponse response = new SlashCommandResponse() { response_type = "in_channel" };

        // the "text" parameter contains the input passed to the command. Reformat it as link
        // and do some sanity checking
        string rawMeetingId = parser.Parameters["text"];
        string meetingId = rawMeetingId.Replace("-", String.Empty);
        if (Regex.IsMatch(meetingId, @"m\d+"))
        {
            string meetingUrl = $"https://meeting.teamviewer.com/join/{meetingId}";
            // this is a markdown representation of what is to be rendered as a result of the command
            response.text = $"{parser.Parameters["user_name"]} invites you to join [TeamViewer Meeting {rawMeetingId}]({meetingUrl})";
            return Ok(response);
        }
        else
        {
            response.response_type = "";
            response.text = "Invalid syntax, use `/tvm <meeting-id>` as trigger";
            return Ok(response);
        }
    }
    return BadRequest();
}

The SlashCommandResponse class is quite simple here:

public class SlashCommandResponse
{
    public string text { get; set; }
    public string response_type { get; set; }
}

Adding the new command to Mattermost

To wire this up you need to host the API on a server that is accessible by the Mattermost server (or even put it on the same machine). As an administrator, you can then choose "Integrations" > "Slash Commands" from the Mattermost menu. The config would look something like this:

Once submitted to the server, you'll then receive a page containing the token (which is actually used in the code above):

In the properties you can then choose which hints to display once the command is invoked by your users. And this is what the resulting UX looks like:

Conclusion

With the attached project, setting up custom slash commands for Mattermost (and similar collaboration platforms) is easily done. This allows to integrate with services that are not (yet) supported by your favorite team collab software.


Similar Articles