You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用C#结合Slack新API上传文件?files.upload已弃用

问题:Slack新API文件上传无报错但文件不显示(C#)

我需要通过C#结合Slack新API实现文件上传(files.upload已弃用),以下是我的代码,运行无报错但Slack未显示上传的文件(可能已被删除),请帮忙排查并提供可用示例:

using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using SlackNet;
using SlackNet.WebApi;
using UploadFile.Services;

class Program
{
    static async Task Main()
    {
        string slackToken = "xoxb-my-token"; 
        string channelId = "C0-cnannelid"; 
        string filePath = @"C:\Users\Пользователь\Desktop\test.txt"; 

        string fileName = Path.GetFileName(filePath);
        byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);  

        var api = new SlackServiceBuilder()
            .UseApiToken(slackToken)
            .GetApiClient();

        var getUploadResponse = await api.Files.GetUploadUrlExternal(fileName, fileBytes.Length);
        string uploadUrl = getUploadResponse.UploadUrl;
        string fileId = getUploadResponse.FileId;

        using var httpClient = new HttpClient();
        using var fileContent = new ByteArrayContent(fileBytes);
        fileContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain");

        var uploadResponse = await httpClient.PutAsync(uploadUrl, fileContent);
        uploadResponse.EnsureSuccessStatusCode();

        var uploadedFiles = await api.Files.CompleteUploadExternal(
            new[] { new ExternalFileReference { Id = fileId, Title = fileName } },
            channelId: channelId
        );

        if (uploadedFiles.Count == 0)
        {
            throw new Exception("Ошибка: файл не прикрепился к каналу.");
        }
    }
}

Bot Token权限

  • channels:read
  • chat:write
  • dnd:read
  • files:read
  • files:write
  • groups:read
  • im:read
  • incoming-webhook
  • mpim:read
  • pins:read
  • pins:write
  • remote_files:read
  • remote_files:share
  • remote_files:write

用户令牌权限

  • chat:write
  • files:read
  • files:write
  • pins:read
  • pins:write
  • remote_files:read
  • remote_files:share

排查分析

  1. 频道ID拼写错误:代码中channelId写为C0-cnannelid,存在拼写错误(应为channel),这会导致文件无法关联到目标频道。
  2. 权限缺失:新文件上传API需要Bot Token拥有files:write:user权限,当前配置中未包含该权限,可能导致文件上传后被Slack自动清理。
  3. HTTP请求头不完整:上传文件时未添加Content-Disposition头指定文件名,部分场景下Slack无法识别文件元信息。
  4. SlackNet版本兼容性:若使用的SlackNet版本过旧,可能对新API的支持存在缺陷。

修复后的可用示例代码

using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using SlackNet;
using SlackNet.WebApi;

class Program
{
    static async Task Main()
    {
        string slackBotToken = "xoxb-your-valid-token"; 
        string channelId = "C0123456789"; // 修正为正确的频道ID
        string filePath = @"C:\Users\Пользователь\Desktop\test.txt"; 

        string fileName = Path.GetFileName(filePath);
        byte[] fileBytes = File.ReadAllBytes(filePath);  

        // 初始化Slack API客户端
        var api = new SlackServiceBuilder()
            .UseApiToken(slackBotToken)
            .GetApiClient();

        // 获取临时上传URL和文件ID
        var uploadUrlResponse = await api.Files.GetUploadUrlExternal(fileName, fileBytes.Length);
        
        // 上传文件到Slack临时存储
        using var httpClient = new HttpClient();
        using var fileContent = new ByteArrayContent(fileBytes);
        // 添加完整的文件头信息
        fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("text/plain");
        fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = fileName
        };

        var uploadResponse = await httpClient.PutAsync(uploadUrlResponse.UploadUrl, fileContent);
        uploadResponse.EnsureSuccessStatusCode(); // 确保上传请求成功

        // 完成上传并关联到频道
        var completedFiles = await api.Files.CompleteUploadExternal(
            new[] { new ExternalFileReference 
            { 
                Id = uploadUrlResponse.FileId, 
                Title = fileName,
                Comment = "C#新API上传的测试文件" // 可选:添加文件描述
            } },
            channelId: channelId
        );

        if (completedFiles.Count == 0)
        {
            throw new Exception("文件上传成功但未关联到频道");
        }
        else
        {
            Console.WriteLine($"文件上传成功,ID:{completedFiles[0].Id}");
        }
    }
}

额外注意事项

  • 确保在Slack应用后台给Bot Token添加files:write:user权限,并重新安装应用到工作区。
  • 若文件名包含非ASCII字符,需确保Content-Disposition的文件名使用UTF-8编码,避免乱码。
  • 可在关键步骤添加日志输出,打印API返回的详细信息,便于后续排查。

内容的提问来源于stack exchange,提问作者e-ghost

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 02:25:54