Search code examples
c#slackslack-api

How to post a message via Slack-App from c#, as a user not App, with attachment, in a specific channel


I can not for the life of me post a message to another channel than the one I webhooked. And I can not do it as myself(under my slackID), just as the App.

Problem is I have to do this for my company, so we can integrate slack to our own Software. I just do not understand what the "payload" for JSON has to look like (actually I'm doing it exactly like it says on Slack's Website, but it doesn't work at all - it always ignores things like "token", "user", "channel" etc.).

I also do not understand how to use the url-methods like "https://slack.com/api/chat.postMessage" - where do they go? As you might see in my code I only have the webhookurl, and if I don't use that one I can not post to anything. Also I do not understand how to use arguments like a token, specific userId, a specific channel... - if I try to put them in the Payload they are just ignored, it seems.

Okay, enough whining! I'll show you now what I got so far. This is from someone who posted this online! But I changed and added a few things:

public static void Main(string[] args)
        {
            Task.WaitAll(IntegrateWithSlackAsync());
        }

        private static async Task IntegrateWithSlackAsync()
        {
            var webhookUrl = new Uri("https://hooks.slack.com/services/TmyHook");  
            var slackClient = new SlackClient(webhookUrl);
            while (true)
            {
                Console.Write("Type a message: ");
                var message = Console.ReadLine();
                Payload testMessage = new Payload(message);
                var response = await slackClient.SendMessageAsync(testMessage);
                var isValid = response.IsSuccessStatusCode ? "valid" : "invalid";
                Console.WriteLine($"Received {isValid} response.");
                Console.WriteLine(response);
            }
        }
    }
}

public class SlackClient
{
        private readonly Uri _webhookUrl;
        private readonly HttpClient _httpClient = new HttpClient {};

        public SlackClient(Uri webhookUrl)
        {
            _webhookUrl = webhookUrl;
        }

        public async Task<HttpResponseMessage> SendMessageAsync(Payload payload)
        {

            var serializedPayload = JsonConvert.SerializeObject(payload);

            var stringCont = new StringContent(serializedPayload, Encoding.UTF8, "application/x-www-form-urlencoded");

            var response = await _httpClient.PostAsync(_webhookUrl, stringCont);

            return response;
        }
    }
}

I made this class so I can handle the Payload as an Object:

    public class Payload
{
    public string token = "my token stands here";
    public string user = "my userID";
    public string channel = "channelID";
    public string text = null;

    public bool as_user = true;


    public Payload(string message)
    {
        text = message;
    }
}

I would be so appreciative for anyone who could post a complete bit of code that really shows how I would have to handle the payload. And/or what the actual URL would look like that gets send to slack... so I maybe can understand what the hell is going on :)


Solution

  • 1. Incoming webhook vs. chat.postMessage

    The incoming webhook of a Slack app is always fixed to a channel. There is legacy variant of the Incoming Webhook that supports overriding the channel, but that has to be installed separately and will not be part of your Slack app. (see also this answer).

    So for your case you want to use the web API method chat.postMessage instead.

    2. Example implementation

    Here is a very basic example implementation for sending a message with chat.postMessage in C#. It will work for different channels and messages will be send as the user who owns the token (same that installed the app), not the app.

    using System;
    using System.Net;
    using System.Collections.Specialized;
    using System.Text;
    
    public class SlackExample
    {    
        public static void SendMessageToSlack()
        {        
            var data = new NameValueCollection();
            data["token"] = "xoxp-YOUR-TOKEN";
            data["channel"] = "blueberry";        
            data["as_user"] = "true";           // to send this message as the user who owns the token, false by default
            data["text"] = "test message 2";
            data["attachments"] = "[{\"fallback\":\"dummy\", \"text\":\"this is an attachment\"}]";
    
            var client = new WebClient();
            var response = client.UploadValues("https://slack.com/api/chat.postMessage", "POST", data);
            string responseInString = Encoding.UTF8.GetString(response);
            Console.WriteLine(responseInString);        
        }
    
        public static void Main()
        {
            SendMessageToSlack();
        }
    }
    

    This is a very rudimentary implementation using synchronous calls. Check out this question for how to use the more advanced asynchronous approach.