Integrating with Slack

We’ve been using Slack for a while now and we find it really useful when sending a receipt notification: an automated, pre-formatted message from an application. For example, you might want Dropbox to notify you after a file is copied to a certain directory.

In one of our projects, we are performing some back office task of importing files from an external source. It’s a lengthy and repetitive chore so I decided to create a nifty tool to automate the task.  Everything works great except that we have to constantly remote the server to check whether the import is finished. I figure that this would be a perfect use case for Slack APIs. Slack has an open and well-documented APIs. All I needed was to use web hooks which is basically just HTTP calls. There are several third-party library for .NET that encapsulate Slack’s API calls that can be found here. I highly recommend that you go plain vanilla and use plain HTTP calls. The steps are fairly trivial: setup your incoming web hook integration here (login needed). Once done, copy your web hook URL. Send a POST request with a JSON payload to your web hook URL.

So here’s how I did it. First, following the DRY principle, I have a base class for all of the basic HTTP calls. Below is a snapshot of my base class. You might want to add more methods like Get or Put for GET and PUT HTTP methods, respectively. Take notice of  the `SerializeContent` method. That’s how we will serialise local objects to JSON.

    public abstract class BaseSyncService : BaseService {
 
        private HttpClient _HttpClient;
        public HttpClient HttpClient {
            get {
                if (_HttpClient == null)
                    _HttpClient = new HttpClient {
                        BaseAddress = new Uri(BuildAPIURL())
                    };
 
                return _HttpClient;
            }
        }
 
        private string BuildAPIURL() {
            return ConfigSettings("APIEndPointURL");
        }
 
        protected virtual HttpContent SerializeContent(object obj) {
            return new StringContent(new JavaScriptSerializer().Serialize(obj), Encoding.UTF8, "application/json");
        }
 
        public virtual async Task Post(string path, HttpContent content) {
            using (HttpClient) {
 
                HttpResponseMessage response = new HttpResponseMessage();
                var result = await _HttpClient.PostAsync(path, content);
 
                return result.Content.ReadAsStringAsync().Result;
            }
        }
 
    }

So I can make a derived class called SlackSyncService, which looks like something like this:

    public class SlackSyncService : BaseSyncService {
        public async Task Notify(string message) {
            return await Post ("", SerializeContent(new { 
                                                        text        = message,
                                                        username    = "Import Bot",
                                                        icon_emoji  = ":thumbsup:"
                                                    }));
        }
    }

Now we’re getting somewhere. Keep in mind that our Post method is awaitable which will beautifully wait for Slack’s API response. Additionally, we can use .NET’s anonymous type to act as a container for our data. This can be serialised to JSON perfectly. There are so many settings to customise your post. You can find everything here.

Now I can just call this service class somewhere in my ViewModel:

        private async Task NotifySlack() {
            if (ShouldNotifySlack) {
                try {
                    await new SlackSyncService().Notify(String.Format("Files successfully imported! Total import time is {0}", ElapsedTime));
                } catch (Exception exception) {
                    EventHandler onExceptionFileImport = OnExceptionFileImport;
                    if (onExceptionFileImport != null)
                        onExceptionFileImport(this, exception.Message);
                }
            }
        }

(I know some of you are probably wondering why I seem to use new keyword willy-nilly and that this is anti-pattern but I have my reasons and it is a good topic for a separate blog post).

That’s it. Adding Slack integration to a .NET app is really easy and fun. It’s a great weekend project. Happy coding!