为什么将文件上传到 Slack 的两种(几乎)相似的方法(使用 c#)会导致不同的结果?
Why do two (almost) similar methods(using c#) of uploading a file to Slack cause different outcomes?
所以这个问题让我很困惑。我将 post 相当多的代码来解释这一点。首先,我有 "old" 版本的代码 (c#),我用它来 post 消息和文件到 Slack。这段代码对我来说很好用!感兴趣的方法如下:
public class PostMessage
{
private string _token = "xoxp-MyToken";
public string token { get { return _token; } }
public string channel { get; set; }
public string text { get; set; }
public MultipartFormDataContent UploadFile()
{
var requestContent = new MultipartFormDataContent();
var fileContent = new StreamContent(GetFile.ReadFile());
requestContent.Add(new StringContent(token), "token");
requestContent.Add(new StringContent(channel), "channels");
requestContent.Add(fileContent, "file", Path.GetFileName(GetFile.path));
return requestContent;
}
public static class GetFile
{
public static string path = @"C:\Users\f.held\Desktop\Held-Docs\Download.jpg";
public static FileStream ReadFile()
{
FileInfo fileInfo = new FileInfo(path);
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
return fs;
}
}
这是我的客户:
public class SlackClient
{
public Uri _method { get; set; }
private readonly HttpClient _httpClient = new HttpClient {};
public SlackClient(Uri webhookUrl)
{
_method = webhookUrl;
}
public async Task<HttpResponseMessage> UploadFileAsync(MultipartFormDataContent requestContent)
{
var response = await _httpClient.PostAsync(_method, requestContent);
return response;
}
}
我在这个 Main 中调用所有这些:
public static void Main(string[] args)
{
Task.WaitAll(TalkToSlackAsync());
private static async Task TalkToSlackAsync()
{
var webhookUrl = new Uri("https://slack.com/api/files.upload");
var slackClient = new SlackClient(webhookUrl);
PostMessage PM = new PostMessage();
PM.channel = "DCW21NBHD";
var cont = PM.UploadFile();
var response = await slackClient.UploadFileAsync(cont);
string content = await response.Content.ReadAsStringAsync();
}
}
到目前为止,一切顺利!但现在它变得有趣了。我构建了一个类似的版本,其中我使用了 Newtonsoft 的 Json NuGet-package
现在,首先是代码:
客户:
public async Task<HttpResponseMessage> SendFileAsync(MultipartFormDataContent requestContent)
{
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "xoxp-MyToken");
var response = await _httpClient.PostAsync(UriMethod, requestContent);
return response;
}
同样的Filestram-读取文件的方法:
public class Message
{
public class GetFile // Just pass a path here as parameter!
{
public static string path = @"C:\Users\f.held\Desktop\Held-Docs\Download.jpg";
public static FileStream ReadFile()
{
FileInfo fileInfo = new FileInfo(path);
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
return fs;
}
}
我连载的Json-class:
public class JsonObject
{
[JsonProperty("file")]
public string file { get; set; }
[JsonProperty("channels")]
public string channels { get; set; }
}
和主要的:
class MainArea
{
public static void Main( string[] args)
{
try
{
Task.WaitAll(SendMessage());
}
catch(Exception dudd)
{
Console.WriteLine(dudd);
Console.ReadKey();
}
}
private static async Task SendMessage()
{
var client = new BpsHttpClient("https://slack.com/api/files.upload");
JsonObject JO = new JsonObject();
JO.channels = "DCW21NBHD";
var Json = JsonConvert.SerializeObject(JO, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
var StringJson = new StringContent(Json, Encoding.UTF8, "multipart/form-data");
var DeSon = JsonConvert.DeserializeObject(Json);
Console.WriteLine(DeSon);
Console.ReadKey();
var requestContent = new MultipartFormDataContent();
var fileContent = new StreamContent(Message.GetFile.ReadFile());
requestContent.Add(fileContent, "file", Path.GetFileName(Message.GetFile.path));
requestContent.Add(StringJson);
var ResponseFile = await client.SendFileAsync(requestContent);
Console.WriteLine(ResponseFile);
Console.ReadKey();
}
}
所以,两个 SEEM 都可以工作。但是这些方法中的后者不会 post 文件到声明的频道 - 它只是将它上传到 Slack。这很好,因为我可以使用 'public_url' 在任何渠道上宣传它。但是 - BIG BUT - 使用第一种方法,它会立即将其加载到我的频道!它在我从 Slack 得到的回复中告诉我。两者的响应完全相同——显然除了时间戳和 file_id 等。但是结局不一样!
这里是旧版回复的结尾:
"shares":{"private":{"DCW21NBHD":[{"reply_users":[],"reply_users_count":0,"reply_count":0,"ts":"1544025773.001700"}]}},"channels":[],"groups":[],"ims":["DCW21NBHD"]}}
这是新版本的答案:
"shares":{},"channels":[],"groups":[],"ims":[]}}
现在好了,为什么在上帝的绿色地球上,一种方法可以做到而另一种方法却不能? :D
感谢任何对此有一定见解和知识的人 "issue" 并愿意分享!
如 files.upload
的文档所述:
Present arguments as parameters in application/x-www-form-urlencoded
querystring or POST body. This method does not currently accept
application/json
.
所以这不起作用的原因是当此方法不支持 JSON 时,您试图提供 API 参数,例如 channels
作为 JSON .结果是忽略了那些属性,这就是为什么图片上传了,但没有分享到指定的频道。
要修复它,只需像在第一个示例中那样提供您的参数作为 application/x-www-form-urlencoded
查询字符串。
请注意,通常只有 Slack API 方法的一个子集支持使用 JSON 来提供所列参数 here。如果要使用 JSON,请仔细检查 API 方法是否支持它,或者坚持使用 x-www-form-urlencoded
(这是 POST 的标准)安全的一面。
所以这个问题让我很困惑。我将 post 相当多的代码来解释这一点。首先,我有 "old" 版本的代码 (c#),我用它来 post 消息和文件到 Slack。这段代码对我来说很好用!感兴趣的方法如下:
public class PostMessage
{
private string _token = "xoxp-MyToken";
public string token { get { return _token; } }
public string channel { get; set; }
public string text { get; set; }
public MultipartFormDataContent UploadFile()
{
var requestContent = new MultipartFormDataContent();
var fileContent = new StreamContent(GetFile.ReadFile());
requestContent.Add(new StringContent(token), "token");
requestContent.Add(new StringContent(channel), "channels");
requestContent.Add(fileContent, "file", Path.GetFileName(GetFile.path));
return requestContent;
}
public static class GetFile
{
public static string path = @"C:\Users\f.held\Desktop\Held-Docs\Download.jpg";
public static FileStream ReadFile()
{
FileInfo fileInfo = new FileInfo(path);
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
return fs;
}
}
这是我的客户:
public class SlackClient
{
public Uri _method { get; set; }
private readonly HttpClient _httpClient = new HttpClient {};
public SlackClient(Uri webhookUrl)
{
_method = webhookUrl;
}
public async Task<HttpResponseMessage> UploadFileAsync(MultipartFormDataContent requestContent)
{
var response = await _httpClient.PostAsync(_method, requestContent);
return response;
}
}
我在这个 Main 中调用所有这些:
public static void Main(string[] args)
{
Task.WaitAll(TalkToSlackAsync());
private static async Task TalkToSlackAsync()
{
var webhookUrl = new Uri("https://slack.com/api/files.upload");
var slackClient = new SlackClient(webhookUrl);
PostMessage PM = new PostMessage();
PM.channel = "DCW21NBHD";
var cont = PM.UploadFile();
var response = await slackClient.UploadFileAsync(cont);
string content = await response.Content.ReadAsStringAsync();
}
}
到目前为止,一切顺利!但现在它变得有趣了。我构建了一个类似的版本,其中我使用了 Newtonsoft 的 Json NuGet-package
现在,首先是代码:
客户:
public async Task<HttpResponseMessage> SendFileAsync(MultipartFormDataContent requestContent)
{
_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "xoxp-MyToken");
var response = await _httpClient.PostAsync(UriMethod, requestContent);
return response;
}
同样的Filestram-读取文件的方法:
public class Message
{
public class GetFile // Just pass a path here as parameter!
{
public static string path = @"C:\Users\f.held\Desktop\Held-Docs\Download.jpg";
public static FileStream ReadFile()
{
FileInfo fileInfo = new FileInfo(path);
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
return fs;
}
}
我连载的Json-class:
public class JsonObject
{
[JsonProperty("file")]
public string file { get; set; }
[JsonProperty("channels")]
public string channels { get; set; }
}
和主要的:
class MainArea
{
public static void Main( string[] args)
{
try
{
Task.WaitAll(SendMessage());
}
catch(Exception dudd)
{
Console.WriteLine(dudd);
Console.ReadKey();
}
}
private static async Task SendMessage()
{
var client = new BpsHttpClient("https://slack.com/api/files.upload");
JsonObject JO = new JsonObject();
JO.channels = "DCW21NBHD";
var Json = JsonConvert.SerializeObject(JO, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
var StringJson = new StringContent(Json, Encoding.UTF8, "multipart/form-data");
var DeSon = JsonConvert.DeserializeObject(Json);
Console.WriteLine(DeSon);
Console.ReadKey();
var requestContent = new MultipartFormDataContent();
var fileContent = new StreamContent(Message.GetFile.ReadFile());
requestContent.Add(fileContent, "file", Path.GetFileName(Message.GetFile.path));
requestContent.Add(StringJson);
var ResponseFile = await client.SendFileAsync(requestContent);
Console.WriteLine(ResponseFile);
Console.ReadKey();
}
}
所以,两个 SEEM 都可以工作。但是这些方法中的后者不会 post 文件到声明的频道 - 它只是将它上传到 Slack。这很好,因为我可以使用 'public_url' 在任何渠道上宣传它。但是 - BIG BUT - 使用第一种方法,它会立即将其加载到我的频道!它在我从 Slack 得到的回复中告诉我。两者的响应完全相同——显然除了时间戳和 file_id 等。但是结局不一样! 这里是旧版回复的结尾:
"shares":{"private":{"DCW21NBHD":[{"reply_users":[],"reply_users_count":0,"reply_count":0,"ts":"1544025773.001700"}]}},"channels":[],"groups":[],"ims":["DCW21NBHD"]}}
这是新版本的答案:
"shares":{},"channels":[],"groups":[],"ims":[]}}
现在好了,为什么在上帝的绿色地球上,一种方法可以做到而另一种方法却不能? :D
感谢任何对此有一定见解和知识的人 "issue" 并愿意分享!
如 files.upload
的文档所述:
Present arguments as parameters in
application/x-www-form-urlencoded
querystring or POST body. This method does not currently acceptapplication/json
.
所以这不起作用的原因是当此方法不支持 JSON 时,您试图提供 API 参数,例如 channels
作为 JSON .结果是忽略了那些属性,这就是为什么图片上传了,但没有分享到指定的频道。
要修复它,只需像在第一个示例中那样提供您的参数作为 application/x-www-form-urlencoded
查询字符串。
请注意,通常只有 Slack API 方法的一个子集支持使用 JSON 来提供所列参数 here。如果要使用 JSON,请仔细检查 API 方法是否支持它,或者坚持使用 x-www-form-urlencoded
(这是 POST 的标准)安全的一面。