如何使用REST API将附件发布到JIRA?

如何在C#中使用JIRA REST API和HttpWebRequest将附件发布到JIRA?

从/ rest / api / 2 / issue / {issueIdOrKey} / attachments下的文档 :

POST

为问题添加一个或多个附件。

此资源需要一个多部分post。 媒体类型的multipart / form-data在RFC 1867中定义。大多数客户端库都有类使得处理多部分post变得简单。 例如,在Java中,Apache HTTP Components库提供了一个MultiPartEntity,使得提交多部分POST变得简单。

为了防止XSRF攻击,因为此方法接受multipart / form-data,所以它具有XSRF保护。 这意味着您必须提交X-Atlassian-Token标头:nocheck请求,否则将被阻止。

包含附件的multipart / form-data参数的名称必须是“file”

上传名为“myfile.txt”的文件以发布REST-123的简单示例:

curl -D- -u admin:admin -X POST -H“X-Atlassian-Token:nocheck”-F“file=@myfile.txt” http://myhost.test/rest/api/2/issue/TEST -123 /附件


我有

foreach (JIRAAttachments attachm in attachments.attachments) { request = HttpWebRequest.Create( logInformation.GetUri() + "/rest/api/2/issue/" + key + "/attachments" ) as HttpWebRequest; request.Headers.Add("Authorization: Basic " + logInformation.GetEncodeAuthentication()); request.Method = "POST"; request.ContentType = "multipart/form-data"; request.Headers.Add("X-Atlassian-Token: nocheck file=@" + Path.GetFullPath(@"..\Attachments\" + attachm.filename)); request.KeepAlive = true; request.Proxy = wp; response = (HttpWebResponse)request.GetResponse(); Stream s = response.GetResponseStream(); FileStream fs = new FileStream(Path.GetFullPath(@"..\Attachments\" + attachm.filename), FileMode.Open); byte[] write = new byte[256]; int count = fs.Read(write, 0, write.Length); while (count > 0) { s.Write(write, 0, count); count = fs.Read(write, 0, write.Length); } fs.Close(); s.Close(); response.Close(); } 

但它返回404错误…

解决了你的问题:

 var boundary = string.Format("----------{0:N}", Guid.NewGuid()); System.IO.MemoryStream content = new MemoryStream(); var writer = new StreamWriter(content); foreach (var att in attachments) { writer.WriteLine("--{0}", boundary); writer.WriteLine("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"", "file", Path.GetFileName(att["filename"])); writer.WriteLine("Content-Type: {0}", att.ContentType); writer.WriteLine(); writer.Flush(); att.Stream.CopyTo(content); writer.WriteLine(); } writer.WriteLine("--" + boundary + "--"); writer.Flush(); content.Seek(0, SeekOrigin.Begin); HttpWebRequest oRequest = null; oRequest = (HttpWebRequest)HttpWebRequest.Create(string.Format(RestBaseURI + "issue/{0}/attachments", item.Key)); oRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary); oRequest.Method = "POST"; oRequest.Headers.Add("Authorization", AuthData); oRequest.Headers.Add("X-Atlassian-Token", "nocheck"); oRequest.UseDefaultCredentials = true; oRequest.KeepAlive = true; oRequest.ContentLength = content.Length; using (var oStream = oRequest.GetRequestStream()) { content.CopyTo(oStream); } using (var oResponse = (HttpWebResponse)oRequest.GetResponse()) { using (var reader = new StreamReader(oResponse.GetResponseStream())) { var responseData = reader.ReadToEnd(); var data = JObject.Parse(responseData); } } 

PS:thanks2mod删除我以前的post! 很好……

OP的代码中存在一些错误。

使用@mabu提供的代码段和我在http://www.briangrinstead.com/blog/multipart-form-post-in-c上找到的代码,这里有一个*function**代码块上传附件到Jira。

 public bool AddAttachments(string issueKey, IEnumerable filePaths) { string restUrl = Jira.FormatRestUrl(m_JiraId, true); string issueLinkUrl = String.Format("{0}/issue/{1}/attachments", restUrl, issueKey); var filesToUpload = new List(); foreach (var filePath in filePaths) { if (!File.Exists(filePath)) { Jira.LogError("File '{0}' doesn't exist", filePath); return false; } var file = new FileInfo(filePath); if (file.Length > 10485760) // TODO Get Actual Limit { Jira.LogError("Attachment too large"); return false; } filesToUpload.Add(file); } if (filesToUpload.Count <= 0) { Jira.LogWarning("No file to Upload"); return false; } return PostMultiPart(issueLinkUrl, filesToUpload); } private Boolean PostMultiPart(string restUrl, IEnumerable filePaths) { HttpWebResponse response = null; HttpWebRequest request = null; try { var boundary = string.Format("----------{0:N}", Guid.NewGuid()); var content = new MemoryStream(); var writer = new StreamWriter(content); foreach (var filePath in filePaths) { var fs = new FileStream(filePath.FullName, FileMode.Open, FileAccess.Read); var data = new byte[fs.Length]; fs.Read(data, 0, data.Length); fs.Close(); writer.WriteLine("--{0}", boundary); writer.WriteLine("Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"", filePath.Name); writer.WriteLine("Content-Type: application/octet-stream"); writer.WriteLine(); writer.Flush(); content.Write(data, 0, data.Length); writer.WriteLine(); } writer.WriteLine("--" + boundary + "--"); writer.Flush(); content.Seek(0, SeekOrigin.Begin); request = WebRequest.Create(restUrl) as HttpWebRequest; if (request == null) { Jira.LogError("Unable to create REST query: {0}", restUrl); return false; } request.Method = "POST"; request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary); request.Accept = "application/json"; request.Headers.Add("Authorization", "Basic " + m_EncodedCredential); request.Headers.Add("X-Atlassian-Token", "nocheck"); request.ContentLength = content.Length; using (Stream requestStream = request.GetRequestStream()) { content.WriteTo(requestStream); requestStream.Close(); } using (response = request.GetResponse() as HttpWebResponse) { if (response.StatusCode != HttpStatusCode.OK) { var reader = new StreamReader(response.GetResponseStream()); Jira.LogError("The server returned '{0}'\n{1}", response.StatusCode, reader.ReadToEnd()); return false; } return true; } } catch (WebException wex) { if (wex.Response != null) { using (var errorResponse = (HttpWebResponse)wex.Response) { var reader = new StreamReader(errorResponse.GetResponseStream()); Jira.LogError("The server returned '{0}'\n{1}).", errorResponse.StatusCode, reader.ReadToEnd()); } } if (request != null) { request.Abort(); } return false; } finally { if (response != null) { response.Close(); } } } 

我真的不想处理所有那些boundary东西,所以这是我的镜头。 这适用于Confluence,其API看起来与Jira相同。

感谢ASP.NET WebApi的 Michael Teper :如何使用WebApi HttpClient和Jeff Caron(上图) 执行带文件上传的多部分post 。

 var contents = "some long HTML that I wanted to upload"; var fileName = "Some fancy file name.html"; using (var client = new HttpClient()) { var uri = new Uri(URL); client.BaseAddress = new Uri(URL); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Authorization = authorization; client.DefaultRequestHeaders.Add("X-Atlassian-Token", "nocheck"); var uriPath = String.Format(AttachmentPath, pageId); var content = new MultipartFormDataContent(); var fileContent = new StringContent(contents); // also tested to work: // var fileContent = new ByteArrayContent(Encoding.UTF8.GetBytes(contents)); content.Add(fileContent, "file", fileName); var response = await client.PostAsync(uriPath, content); if (response.IsSuccessStatusCode) { return TaskResult.Success(null, response.ReasonPhrase); } else { return TaskResult.Failure("Service responded with Status Code: " + response.StatusCode + Environment.NewLine + "Reason Phrase: " + response.ReasonPhrase); } } 

您还可以使用Restsharp,如下所示

 using System; using System.Collections.Generic; using System.IO; using System.Net; using Jira using RestSharp; using RestSharp.Authenticators; namespace Jira { class Program { static void Main(string[] args) { var client = new RestClient("http://{URL}/rest/api/2"); var request = new RestRequest("issue/", Method.POST); client.Authenticator = new HttpBasicAuthenticator("user", "pass"); var issue = new Issue { fields = new Fields { description = "Issue Description", summary = "Issue Summary", project = new Project { key = "KEY" }, issuetype = new IssueType { name = "ISSUE_TYPE_NAME" } } }; request.AddJsonBody(issue); var res = client.Execute(request); if (res.StatusCode == HttpStatusCode.Created) { Console.WriteLine("Issue: {0} successfully created", res.Data.key); #region Attachment request = new RestRequest(string.Format("issue/{0}/attachments", res.Data.key), Method.POST); request.AddHeader("X-Atlassian-Token", "nocheck"); var file = File.ReadAllBytes(@"C:\FB_IMG_1445253679378.jpg"); request.AddHeader("Content-Type", "multipart/form-data"); request.AddFileBytes("file", file, "FB_IMG_1445253679378.jpg", "application/octet-stream"); var res2 = client.Execute(request); Console.WriteLine(res2.StatusCode == HttpStatusCode.OK ? "Attachment added!" : res2.Content); #endregion } else Console.WriteLine(res.Content); } } public class Issue { public string id { get; set; } public string key { get; set; } public Fields fields { get; set; } } public class Fields { public Project project { get; set; } public IssueType issuetype { get; set; } public string summary { get; set; } public string description { get; set; } } public class Project { public string id { get; set; } public string key { get; set; } } public class IssueType { public string id { get; set; } public string name { get; set; } } } 

整个代码在gist上https://gist.github.com/gandarez/c2c5b2b27dbaf62a0d634253529bcb59