如何通过 C# 中的 Slack-App 在 Slack 上上传任何文件

How to upload any file on Slack via Slack-App in c#

我需要有关将文件上传到 Slack 的帮助。

到目前为止,我有一个 Slack-App 正在使用我的代码(如下)。但我所能做的就是 post 条消息。我无法将图像附加到消息中 - 因为我不明白如何使用所谓的 "methods" 并且语法 Slack 在他们的 API 页面上是 "showing"。

这会创建我的 "content" 并在其下方创建一个流,用于读取我可以上传的文件:

    public class PostMessage
    {


        public FormUrlEncodedContent Content(string message, string file)
        {
            var values = new Dictionary<string, string>
            {
                {"token", "xoxp-myToken"},
                { "username", "X"},         
                { "channel", "myChannel"},
                { "as_user", "false"},     
                {"text", message},
                { "content", file},
                { "attachments","[{ \"fallback\":\"dummy\", \"text\":\"this is a waste of time\"}]"}
            };

            var content = new FormUrlEncodedContent(values);

            return content;
        }
    }

    public class PostFile
    {
        String path = @"C:\Users\f.held\Desktop\Held-Docs\dagged.jpg";

        public string ReadImageFile()
        {            
            FileInfo fileInfo = new FileInfo(path);
            long imageFileLength = fileInfo.Length;
            FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
            BinaryReader br = new BinaryReader(fs);
            byte[] imageData = br.ReadBytes((int)imageFileLength);
            var str = Encoding.Default.GetString(imageData);
            return str;
        }
    }
}  

通信的客户端:

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

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

        public async Task<HttpResponseMessage> SendMessageAsync(FormUrlEncodedContent content)
        {
            var response = await _httpClient.PostAsync(_webhookUrl, content);

            return response;
        }    
     }
}

主线:

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

private static async Task IntegrateWithSlackAsync()
{
    var webhookUrl = new Uri("https://slack.com/api/files.upload");
    var slackClient = new SlackClient(webhookUrl);
    PostMessage PM = new PostMessage();
    PostFile PF = new PostFile();


    while (true)
    {
        Console.Write("Type a message: ");
        var message = Console.ReadLine();
        var testFile = PF.ReadImageFile();
        FormUrlEncodedContent payload = PM.Content(message, testFile);
        var response = await slackClient.SendMessageAsync(payload);
        var isValid = response.IsSuccessStatusCode ? "valid" : "invalid";
        Console.WriteLine($"Received {isValid} response.");
        Console.WriteLine(response);
        response.Dispose();
    }
}

} }

如果有人有关于上传必须是什么样子的示例。或者更好,

如果有人真的能解释这些 Slack-Messages 必须具有的语法。

那就太好了!我仍然不知道我应该把所谓的放在哪里以及如何放 "Accepted content types: multipart/form-data, application/x-www-form-urlencoded"到我上传。我只是找不到这方面的例子...

编辑:

让我非常困惑的是 Slack 声明他们有一个额外的方法叫做 file.upload - 但我们不应该再使用它了,我们应该只使用 postMessage

但是我如何 "pack" 邮件中的文件?我的语法似乎总是不正确。尤其是 "content"... 我就是想不通 C# 代码应该是什么样子。我在哪里声明前面提到的 "content type"?

另一个问题是,它总是通过 - 意味着我从服务器收到 200 响应。但它从不显示文件(这可能意味着语法已关闭)或者我得到 200 响应,但该消息从未在 Slack 中显示。

消息中的图片

如果您想在邮件中包含图片(连同一些文本),您可以将图片作为邮件附件添加到使用 chat.postMessage 发送的普通邮件中。

为此,您需要 public URL 图片和 link 以及 image_url 属性 附件。该附件还可以包含文本,您可以在邮件中添加多个附件。

这是它的样子:

下面是这条消息在 JSON 中的样子:

{
    "channel": "test",
    "text": "This is a message example with images in the attachment",
    "attachments": [
        {
            "fallback": "game over",
            "text": "This is some text in the attachement",
            "image_url": "https://i.imgur.com/jO9N3eJ.jpg"

        }
    ]
}

正在上传图片

图像 URL 需要 public 可以在 Internet 上访问。因此,您需要将图像文件托管在 public 网络服务器上或将其上传到图像云服务(例如 imgur.com)。

您还可以使用 Slack 作为图像的云服务。这是它的工作原理:

  1. 上传到 Slack:使用 files.upload

  2. 将您的图像上传到您的 Slack 工作区
  3. 获取public URL:获取public URL 用于files.sharedPublicURL 的图像文件。通常 Slack 上的所有文件都是私有的,但您只能使用 public URL 作为消息附件。

  4. 发送消息:将您的图像作为附件包含在消息中:使用图像文件的 permalink_public 属性 作为 image_url[=23= 的值]

示例代码

这是一个完整的 C# 示例,首先将图像上传到 Slack,然后在消息中使用它。

注意:此示例需要 Newtonsoft.Json

using System;
using System.Net;
using System.Collections.Specialized;
using System.Text;
using Newtonsoft.Json;

public class SlackExample
{
    // classes for converting JSON respones from API method into objects
    // note that only those properties are defind that are needed for this example

    // reponse from file methods
    class SlackFileResponse
    {
        public bool ok { get; set; }
        public String error { get; set; }
        public SlackFile file { get; set; }
    }

    // a slack file
    class SlackFile
    {
        public String id { get; set; }        
        public String name { get; set; }
        public String permalink_public { get; set; }
    }

    // reponse from message methods
    class SlackMessageResponse
    {
        public bool ok { get; set; }
        public String error { get; set; }
        public String channel { get; set; }
        public String ts { get; set; }        
    }

    // a slack message attachment
    class SlackAttachment
    {
        public String fallback { get; set; }
        public String text { get; set; }
        public String image_url { get; set; }
    }

    // main method with logic
    public static void Main()
    {
        String token = "xoxp-YOUR-TOKEN";


        /////////////////////
        // Step 1: Upload file to Slack

        var parameters = new NameValueCollection();

        // put your token here
        parameters["token"] = token;

        var client1 = new WebClient();
        client1.QueryString = parameters;
        byte[] responseBytes1 = client1.UploadFile(
                "https://slack.com/api/files.upload",
                "C:\Temp\Stratios_down.jpg"
        );

        String responseString1 = Encoding.UTF8.GetString(responseBytes1);

        SlackFileResponse fileResponse1 = 
            JsonConvert.DeserializeObject<SlackFileResponse>(responseString1);

        String fileId = fileResponse1.file.id;


        /////////////////////
        // Step 2: Make file public and get the URL

        var parameters2 = new NameValueCollection();
        parameters2["token"] = token;
        parameters2["file"] = fileId;

        var client2 = new WebClient();
        byte[] responseBytes2 = client2.UploadValues("https://slack.com/api/files.sharedPublicURL", "POST", parameters2);

        String responseString2 = Encoding.UTF8.GetString(responseBytes2);

        SlackFileResponse fileResponse2 =
            JsonConvert.DeserializeObject<SlackFileResponse>(responseString2);

        String imageUrl = fileResponse2.file.permalink_public;


        /////////////////////
        // Step 3: Send message including freshly uploaded image as attachment

        var parameters3 = new NameValueCollection();
        parameters3["token"] = token;
        parameters3["channel"] = "test_new";        
        parameters3["text"] = "test message 2";

        // create attachment
        SlackAttachment attachment = new SlackAttachment();
        attachment.fallback = "this did not work";
        attachment.text = "this is anattachment";
        attachment.image_url = imageUrl;
        SlackAttachment[] attachments = { attachment };        
        parameters3["attachments"] = JsonConvert.SerializeObject(attachments);

        var client3 = new WebClient();
        byte[] responseBytes3 = client3.UploadValues("https://slack.com/api/chat.postMessage", "POST", parameters3);

        String responseString3 = Encoding.UTF8.GetString(responseBytes3);

        SlackMessageResponse messageResponse =
            JsonConvert.DeserializeObject<SlackMessageResponse>(responseString3);

    }
}

这是一个较短的工作示例,展示了如何仅使用 C# 将任何文件上传到 Slack。该示例还将自动共享给定频道的文件。

我已经包含了从 JSON 转换 API 响应的逻辑,这将始终需要确定 API 调用是否成功。

注意:此示例需要 Newtonsoft.Json

using System;
using System.Net;
using System.Collections.Specialized;
using System.Text;
using Newtonsoft.Json;

public class SlackExample
{
    // classes for converting JSON respones from API method into objects
    // note that only those properties are defind that are needed for this example

    // reponse from file methods
    class SlackFileResponse
    {
        public bool ok { get; set; }
        public String error { get; set; }
        public SlackFile file { get; set; }
    }

    // a slack file
    class SlackFile
    {
        public String id { get; set; }
        public String name { get; set; }        
    }

    // main method with logic
    public static void Main()
    {
        var parameters = new NameValueCollection();

        // put your token here
        parameters["token"] = "xoxp-YOUR-TOKEN";
        parameters["channels"] = "test";

        var client = new WebClient();
        client.QueryString = parameters;
        byte[] responseBytes = client.UploadFile(
                "https://slack.com/api/files.upload",
                "D:\temp\Stratios_down.jpg"
        );

        String responseString = Encoding.UTF8.GetString(responseBytes);

        SlackFileResponse fileResponse =
            JsonConvert.DeserializeObject<SlackFileResponse>(responseString);
    }
}

关于内容类型:它们是 HTTP 请求 header 的一部分,可以在 WebClient object 中手动设置(另请参阅 this answer)。但是,对于我们的案例,您可以忽略它,因为 WebClient 用于 POST 请求的默认内容类型将正常工作。

另请参阅 this answer,了解如何使用 WebClient class 上传文件。

这是另一个将文件上传到 Slack 的完整示例,这次使用 async 方法和 HttpClient

注意:此示例需要 Newtonsoft.Json

using Newtonsoft.Json;
using System;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;

namespace SlackExample
{
    class UploadFileExample
    {
        private static readonly HttpClient client = new HttpClient();

        // classes for converting JSON respones from API method into objects
        // note that only those properties are defind that are needed for this example

        // reponse from file methods
        class SlackFileResponse
        {
            public bool ok { get; set; }
            public String error { get; set; }
            public SlackFile file { get; set; }
        }

        // a slack file
        class SlackFile
        {
            public String id { get; set; }
            public String name { get; set; }
        }

        // sends a slack message asynchronous
        // throws exception if message can not be sent
        public static async Task UploadFileAsync(string token, string path, string channels)
        {
            // we need to send a request with multipart/form-data
            var multiForm = new MultipartFormDataContent();

            // add API method parameters
            multiForm.Add(new StringContent(token), "token");
            multiForm.Add(new StringContent(channels), "channels");

            // add file and directly upload it
            FileStream fs = File.OpenRead(path);
            multiForm.Add(new StreamContent(fs), "file", Path.GetFileName(path));

            // send request to API
            var url = "https://slack.com/api/files.upload";
            var response = await client.PostAsync(url, multiForm);

            // fetch response from API
            var responseJson = await response.Content.ReadAsStringAsync();

            // convert JSON response to object
            SlackFileResponse fileResponse =
                JsonConvert.DeserializeObject<SlackFileResponse>(responseJson);

            // throw exception if sending failed
            if (fileResponse.ok == false)
            {
                throw new Exception(
                    "failed to upload message: " + fileResponse.error
                );
            }
            else
            {
                Console.WriteLine(
                        "Uploaded new file with id: " + fileResponse.file.id
                );
            }
        }

        static void Main(string[] args)
        {
            // upload this file and wait for completion
            UploadFileAsync(
                "xoxp-YOUR-TOKEN",
                "C:\temp\Stratios_down.jpg",
                "test"
            ).Wait();

            Console.ReadKey();

        }
    }

}