{"id":5911,"date":"2015-09-06T07:44:02","date_gmt":"2015-09-06T07:44:02","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/2015\/09\/06\/integrating-with-slack-using-asp-net-webhooks-preview\/"},"modified":"2023-09-19T11:25:42","modified_gmt":"2023-09-19T18:25:42","slug":"integrating-with-slack-using-asp-net-webhooks-preview","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/integrating-with-slack-using-asp-net-webhooks-preview\/","title":{"rendered":"Integrating with Slack Using ASP.NET WebHooks Preview"},"content":{"rendered":"<p>In the blog <a href=\"http:\/\/blogs.msdn.com\/b\/webdev\/archive\/2015\/09\/04\/introducing-microsoft-asp-net-webhooks-preview.aspx\">Introducing Microsoft ASP.NET WebHooks Preview<\/a>, we gave an overview of how to work with Microsoft ASP.NET WebHooks. <a href=\"https:\/\/slack.com\/\">Slack<\/a> provides an interesting model where you can set up a WebHook to be fired when a certain trigger word is used in one of their messaging channels. In addition, it is possible for the WebHook to send data <em>back<\/em> to the channel which is very useful. For example, if you have a trigger word <strong>AskMe:<\/strong> then you can get the WebHook to respond like this:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/09\/0728.SlackChannelMini_thumb_62E9B802.png\"><img decoding=\"async\" title=\"SlackChannelMini\" style=\"border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;border-top-width: 0px;margin-right: auto\" border=\"0\" alt=\"SlackChannelMini\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/09\/0728.SlackChannelMini_thumb_62E9B802.png\" width=\"400\" height=\"228\" \/><\/a><\/p>\n<h3>WebHook Configuration<\/h3>\n<p>To setup <a href=\"https:\/\/api.slack.com\/outgoing-webhooks\">Slack WebHooks<\/a> you need a Slack account. Then you configure the WebHook using what they call an <strong>Integration<\/strong> as follows:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/16\/2018\/10\/2477.SlackIntegrations_3BAF6ECD.png\"><img decoding=\"async\" title=\"SlackIntegrations\" style=\"border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;border-top-width: 0px;margin-right: auto\" border=\"0\" alt=\"SlackIntegrations\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/09\/7608.SlackIntegrations_thumb_704FCB08.png\" width=\"600\" height=\"462\" \/><\/a><\/p>\n<p>Pick the <strong>Outgoing WebHooks integration, <\/strong>select <strong>Add Outgoing WebHooks Integration<\/strong> and look for the fields <strong>Trigger Words<\/strong>, <strong>URLs<\/strong>, and <strong>Token<\/strong>. Fill in whatever trigger words and WebHook URI, and copy the <strong>Token<\/strong> for use later. The URI must have the form <b>https:\/\/&lt;host&gt;\/api\/webhooks\/incoming\/slack<\/strong><\/b><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/16\/2018\/10\/2018.SlackWebHookConfiguration_24F02744.png\"><img decoding=\"async\" title=\"SlackWebHookConfiguration\" style=\"border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;border-top-width: 0px;margin-right: auto\" border=\"0\" alt=\"SlackWebHookConfiguration\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/09\/8206.SlackWebHookConfiguration_thumb_644DDAD4.png\" width=\"600\" height=\"488\" \/><\/a><\/p>\n<h3>Configuring Receiver<\/h3>\n<p>The last part is to configure the WebHook receiver. After having installed the <b><a href=\"https:\/\/www.nuget.org\/packages?q=Microsoft.AspNet.WebHooks.Receivers.Slack\">Microsoft.AspNet.WebHooks.Receivers.Slack<\/a><\/b> Nuget package into your ASP.NET application, this happens exactly like show in the blog <a href=\"http:\/\/blogs.msdn.com\/b\/webdev\/archive\/2015\/09\/04\/introducing-microsoft-asp-net-webhooks-preview.aspx\">Introducing Microsoft ASP.NET WebHooks Preview<\/a>:<\/p>\n<p>The first part of the configuration is done in <strong>WebApiConfig.cs<\/strong> where you add line 17 like this:<\/p>\n<div id=\"codeSnippetWrapper\">\n<div id=\"codeSnippet\">\n<pre><span id=\"lnum1\" style=\"color: #606060\">   1:<\/span> <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">static<\/span> <span style=\"color: #0000ff\">class<\/span> WebApiConfig<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum2\" style=\"color: #606060\">   2:<\/span> {<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum3\" style=\"color: #606060\">   3:<\/span>     <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">static<\/span> <span style=\"color: #0000ff\">void<\/span> Register(HttpConfiguration config)<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum4\" style=\"color: #606060\">   4:<\/span>     {<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum5\" style=\"color: #606060\">   5:<\/span>         <span style=\"color: #008000\">\/\/ Web API configuration and services<\/span><\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum6\" style=\"color: #606060\">   6:<\/span>&#160; <\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum7\" style=\"color: #606060\">   7:<\/span>         <span style=\"color: #008000\">\/\/ Web API routes<\/span><\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum8\" style=\"color: #606060\">   8:<\/span>         config.MapHttpAttributeRoutes();<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum9\" style=\"color: #606060\">   9:<\/span>&#160; <\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum10\" style=\"color: #606060\">  10:<\/span>         config.Routes.MapHttpRoute(<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum11\" style=\"color: #606060\">  11:<\/span>             name: <span style=\"color: #006080\">&quot;DefaultApi&quot;<\/span>,<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum12\" style=\"color: #606060\">  12:<\/span>             routeTemplate: <span style=\"color: #006080\">&quot;api\/{controller}\/{id}&quot;<\/span>,<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum13\" style=\"color: #606060\">  13:<\/span>             defaults: <span style=\"color: #0000ff\">new<\/span> { id = RouteParameter.Optional }<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum14\" style=\"color: #606060\">  14:<\/span>         );<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum15\" style=\"color: #606060\">  15:<\/span>&#160; <\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum16\" style=\"color: #606060\">  16:<\/span>         <span style=\"color: #008000\">\/\/ Load Slack receiver<\/span><\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum17\" style=\"color: #606060\">  17:<\/span>         config.InitializeReceiveSlackWebHooks();<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum18\" style=\"color: #606060\">  18:<\/span>     }<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum19\" style=\"color: #606060\">  19:<\/span> }<\/pre>\n<p><!--CRLF--><\/div>\n<\/div>\n<p>The second part is to set the secret token so that it can be verified by the receiver. This is done by setting the <strong>MS_WebHookReceiverSecret_Slack<\/strong> app setting for your Web Application to the value of the secret Token obtained from before. As stated in the blog <a href=\"http:\/\/blogs.msdn.com\/b\/webdev\/archive\/2015\/09\/04\/introducing-microsoft-asp-net-webhooks-preview.aspx\">Introducing Microsoft ASP.NET WebHooks Preview<\/a>, the preferred way to do this is to set it in the Azure Portal:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/09\/8836.AzureAppSettings_thumb_27AC7AB1.png\"><img decoding=\"async\" title=\"AzureAppSettings\" style=\"border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;border-top-width: 0px;margin-right: auto\" border=\"0\" alt=\"AzureAppSettings\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/09\/8836.AzureAppSettings_thumb_27AC7AB1.png\" width=\"600\" height=\"322\" \/><\/a><\/p>\n<h3>Defining a Handler<\/h3>\n<p>Slack sends WebHook data in the form of HTML Form data so we read it as a <strong>NameValueCollection<\/strong>. Further, as the Slack WebHook can return data, we use the <strong>Response<\/strong> property on the <strong>WebHookHandlerContext<\/strong> to define the data we want to return. The <strong>SlackResponse<\/strong> is just a helper formatting the response as expected by Slack.<\/p>\n<div id=\"codeSnippetWrapper\">\n<div id=\"codeSnippet\">\n<pre><span id=\"lnum1\" style=\"color: #606060\">   1:<\/span> <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">class<\/span> SlackWebHookHandler : WebHookHandler<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum2\" style=\"color: #606060\">   2:<\/span> {<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum3\" style=\"color: #606060\">   3:<\/span>     <span style=\"color: #0000ff\">public<\/span> <span style=\"color: #0000ff\">override<\/span> Task ExecuteAsync(<span style=\"color: #0000ff\">string<\/span> generator, WebHookHandlerContext context)<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum4\" style=\"color: #606060\">   4:<\/span>     {<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum5\" style=\"color: #606060\">   5:<\/span>         NameValueCollection nvc;<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum6\" style=\"color: #606060\">   6:<\/span>         <span style=\"color: #0000ff\">if<\/span> (context.TryGetData&lt;NameValueCollection&gt;(<span style=\"color: #0000ff\">out<\/span> nvc))<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum7\" style=\"color: #606060\">   7:<\/span>         {<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum8\" style=\"color: #606060\">   8:<\/span>             <span style=\"color: #0000ff\">string<\/span> question = nvc[<span style=\"color: #006080\">&quot;subtext&quot;<\/span>];<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum9\" style=\"color: #606060\">   9:<\/span>             <span style=\"color: #0000ff\">string<\/span> msg = <span style=\"color: #0000ff\">string<\/span>.Format(<span style=\"color: #006080\">&quot;The answer to '{0}' is '{1}'.&quot;<\/span>, question, <span style=\"color: #006080\">&quot;Often&quot;<\/span>);<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum10\" style=\"color: #606060\">  10:<\/span>             SlackResponse reply = <span style=\"color: #0000ff\">new<\/span> SlackResponse(msg);<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum11\" style=\"color: #606060\">  11:<\/span>             context.Response = context.Request.CreateResponse(reply);<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum12\" style=\"color: #606060\">  12:<\/span>         }<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum13\" style=\"color: #606060\">  13:<\/span>         <span style=\"color: #0000ff\">return<\/span> Task.FromResult(<span style=\"color: #0000ff\">true<\/span>);<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum14\" style=\"color: #606060\">  14:<\/span>     }<\/pre>\n<p><!--CRLF--><\/p>\n<pre><span id=\"lnum15\" style=\"color: #606060\">  15:<\/span> }<\/pre>\n<p><!--CRLF--><\/div>\n<\/div>\n<h3>Trying it Out<\/h3>\n<p>Once deployed, we are ready to try this out: In a Slack channel write something like this <strong>AskMe: You there?<\/strong> You should now be called in your handler and see a response on the Slack channel like this:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/16\/2018\/10\/0207.SlackChannel_41F8D60C.png\"><img decoding=\"async\" title=\"SlackChannel\" style=\"border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;border-top-width: 0px;margin-right: auto\" border=\"0\" alt=\"SlackChannel\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2015\/09\/1781.SlackChannel_thumb_3D825545.png\" width=\"604\" height=\"509\" \/><\/a><\/p>\n<p>This should hopefully be enough to get you started receiving WebHooks from Slack using ASP.NET WebHooks Preview.<\/p>\n<p>Have fun!<\/p>\n<p>Henrik<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the blog Introducing Microsoft ASP.NET WebHooks Preview, we gave an overview of how to work with Microsoft ASP.NET WebHooks. Slack provides an interesting model where you can set up a WebHook to be fired when a certain trigger word is used in one of their messaging channels. In addition, it is possible for the [&hellip;]<\/p>\n","protected":false},"author":403,"featured_media":58792,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197],"tags":[34,7505,7506],"class_list":["post-5911","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","tag-asp-net-web-api","tag-asp-net-webhooks","tag-webhooks"],"acf":[],"blog_post_summary":"<p>In the blog Introducing Microsoft ASP.NET WebHooks Preview, we gave an overview of how to work with Microsoft ASP.NET WebHooks. Slack provides an interesting model where you can set up a WebHook to be fired when a certain trigger word is used in one of their messaging channels. In addition, it is possible for the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/5911","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/403"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=5911"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/5911\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=5911"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=5911"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=5911"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}