Slack Outgoing Webhooks
The aim of the game
I built the Slack.Webhooks library so that you could post messages into your Slack account easily, but I wanted to demonstrate how to use it to receive message from slack (and optionally respond with a message).
Required packages for this demo
- Slack.Webhooks
- NancyFX I chose to use self hosted nancy but feel free to use MVC, WebForms or whatever.
The process
Start a new console app (this could just as easily have been a empty asp.net application)
Install dependencies
PM> Install-Package Slack.Webhooks
PM> Install-Package Nancy.Hosting.Self
Setup nancy
Listen for requests on port 1234
static void Main()
{
JsConfig.EmitLowercaseUnderscoreNames = true;
JsConfig.IncludeNullValues = false;
JsConfig.PropertyConvention = JsonPropertyConvention.Lenient;
using (var host = new NancyHost(new Uri("http://localhost:1234")))
{
host.Start();
Console.ReadLine();
}
}
Create a module to handle requests
public class WebhookModule : NancyModule
{
public WebhookModule()
{
Post["/"] = _ =>
{
var model = this.Bind<HookMessage>();
var message = string.Empty;
if (model.Text.ToLower().StartsWith("testbot: hello"))
message = string.Format("@{0} Hello", model.UserName);
if(!string.IsNullOrWhiteSpace(message))
return new SlackMessage {Text = message, Username = "testbot", IconEmoji = Emoji.Ghost};
return null;
};
}
}
and the Model
public class HookMessage
{
public string Token { get; set; }
public string TeamId { get; set; }
public string ChannelId { get; set; }
public string ChannelName { get; set; }
public string UserId { get; set; }
public string UserName { get; set; }
public string Text { get; set; }
public string TriggerWord { get; set; }
}
I may move this model into the library, but it requires a bit of faffing to deserialize the payload from Slack, so I may just keep it seperate for now.
They payload from Slack looks a little like this:
token=XXXXXXXXXXXXXXXXXX
team_id=T0001
team_domain=example
channel_id=C2147483705
channel_name=test
timestamp=1355517523.000005
user_id=U2147483697
user_name=Steve
text=googlebot: What is the air-speed velocity of an unladen swallow?
trigger_word=googlebot:
in order to bind the
channel_id
style field names to
ChannelId
model properties you can create a new implementation of Nancy’s IFieldNameConverter interface. I did this using the String.ToTitleCase extension method from ServiceStack.Text in order to get the result I wanted.
public class TitleCaseFieldNameConverter : IFieldNameConverter
{
public string Convert(string fieldName)
{
return fieldName.ToTitleCase();
}
}
And then register this new type in a new nancy bootstrapper
public class Bootstrapper : DefaultNancyBootstrapper
{
protected override void ApplicationStartup(Nancy.TinyIoc.TinyIoCContainer container, Nancy.Bootstrapper.IPipelines pipelines)
{
container.Register<IFieldNameConverter, TitleCaseFieldNameConverter>();
base.ApplicationStartup(container, pipelines);
}
}
At this point the app should be good to go, all that is left to do is configure a new Outgoing webhook integration to deliver messages containeing trigger word(s) (e.g. testbot:) to your new application.
If you want to do this on your local dev machine I can’t recommend ngrok enough for routing external traffic without having to mess about with routers, dns and firewalls too much.