【问题标题】:How to upload any file on Slack via Slack-App in c#如何通过 C# 中的 Slack-App 在 Slack 上上传任何文件
【发布时间】:2018-11-12 14:20:04
【问题描述】:

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

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

这会创建我的“内容”,在它下面只是一个用于读取我可以上传的文件的流:

    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 必须具有的语法。

那太好了!我仍然不知道我应该在哪里以及如何放置所谓的 “接受的内容类型:multipart/form-data, application/x-www-form-urlencoded” 到我的上传。我只是找不到这方面的例子......

编辑:

让我感到困惑的是,Slack 声明他们有一个名为file.upload 的额外方法——但我们不应该再使用它,我们应该只使用postMessage

但是我如何将文件“打包”到消息中?我的语法似乎总是关闭。尤其是在“内容”方面...... 我只是无法弄清楚 c# 代码的外观。我在哪里声明上述“内容类型”?

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

【问题讨论】:

  • 您能否说明您的目标是什么:您想在您的消息中附加图片还是要将文件上传到 Slack?
  • 嘿,Erik,我需要两者兼得。但是为什么会有区别呢?一切都是文件,对吧?我知道你在我的另一个问题上发布了我只能发布图片的消息。但是 Slack 明确指出文件上传现在被视为消息(看这里:api.slack.com/changelog/2018-05-file-threads-soon-tread)。还是我读错了?当我使用 SlackRTM 上传任何类型的图像或文件时,它的行为似乎没有什么不同......所以?!谢谢!
  • 你是对的。 files.upload 现在正在创建消息,但仍然存在差异。文件上传将仅包含文件,并且文件实际上传到 Slack。相反,您可以在消息中包含多个图像以及文本。并且这些图像没有上传。您只需提供一个 URL 即可。
  • 这是一个显示文件上传和带有图像附件的消息的屏幕截图:i.imgur.com/w5dgw5s.png
  • 好吧...我知道你的意思,但我说的是在我的物理硬盘上上传文件和图像,而不是任何地方都可以在线的东西。而且我必须坚持我的答案,即我想要两者都做:) 上传文件和附有文件的消息。我刚刚测试了我的 FileStream,我的意思是我将它转换回图像并将其写入我的硬盘。它奏效了,所以我的错在我发送的“信息”中的某个地方。或者我实际创建然后编码和发送的对象......但我一无所知。我一直在这个问题上 - 从早上 8 点开始 :(

标签: c# slack slack-api


【解决方案1】:

消息中的图片

如果您想在消息中包含图像(以及一些文本),您可以通过将图像作为消息附件添加到使用chat.postMessage 发送的普通消息中来实现。

为此,您需要图像的公共 URL 以及带有 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 需要在 Internet 上公开访问。因此,您需要将您的图片文件托管在公共网络服务器上或将其上传到图片云服务(例如 imgur.com)。

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

  1. 上传到 Slack:使用 files.upload 将图像上传到 Slack 工作区

  2. 获取公共 URL:使用 files.sharedPublicURL 获取图像文件的公共 URL。通常,Slack 上的所有文件都是私有的,但您只能将公共 URL 用于消息附件。

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

示例代码

这是一个完整的 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);

    }
}

【讨论】:

    【解决方案2】:

    这是一个简短的工作示例,展示了如何仅使用 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 请求标头的一部分,可以在 WebClient 对象中手动设置(另请参阅 this answer)。但是,对于我们的情况,您可以忽略它,因为 WebClient 用于 POST 请求的默认内容类型可以正常工作。

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

    【讨论】:

    • 你是我们凡人中的神 :) 我在开玩笑,但老实说,非常感谢你的帮助!我希望这不仅能帮助我,也能帮助其他人。非常感谢您提供这些清晰的示例,感谢您的所有努力和工作。你的答案清晰而准确,有很好的例子。我可以从中学习。再次,谢谢你。当然,在测试完你的代码后,我会回来投票;)
    • 现在它不会通过 HttpClient 上传。我得到的回应说“好的”。但图像不会在 Slack 中显示。我的上传方法:public async Task&lt;HttpResponseMessage&gt; UploadFile(byte[] file) { var requestContent = new MultipartFormDataContent(); var fileContent = new ByteArrayContent(file); fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data"); requestContent.Add(fileContent, "dagged", "dagged.jpg"); var response = await _httpClient.PostAsync(_webhookUrl, requestContent); return response; }
    • 您的 WebClient-Method 工作正常。我的 HttPClient-Method 在发送带有附加图像的消息时有效。但是当我只想上传任何类型的文件时它不起作用。我总是得到 {"ok":false,"error":"no_file_data"} 好吧,我发现问题似乎是我使用 byte[] 作为内容。其他人似乎也有同样的问题。我不明白为什么,因为 WebClient 也使用字节数组......我很困惑 :D 任何人有一个好主意?
    • 你的方法有几个问题:1)你缺少像token这样的强制API参数2)你不能手动设置多部分,它通过MultipartFormDataContent()自动设置我将添加另一个答案一个完整的异步示例来澄清事情。
    • 请注意,通常最好将所有源更新添加到问题中。人们很难在 cmets 中找到源代码。我为你添加了它。
    【解决方案3】:

    这是将文件上传到 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();
    
            }
        }
    
    }
    

    【讨论】:

    • 您好 Erik,我正在使用 IHttpClientFactory 发布端点并接收图像。然后我使用 MemoryStream 从响应中创建一个位图。现在,我需要将此位图作为附件发送到 slack。除了将图像上传到工作区之外,还有其他解决方法吗?
    • 我也在下面的帖子stackoverflow.com/questions/71442781/…中问过
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    • 1970-01-01
    • 1970-01-01
    • 2022-12-05
    • 2018-05-12
    相关资源
    最近更新 更多