How to POST attachment to JIRA using JIRA REST API and HttpWebRequest in C#?
From the documentation under /rest/api/2/issue/{issueIdOrKey}/attachment
solved your problem:
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 to delete my previous post! nice ...
You're also able to do with Restsharp as follow
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<Issue>(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; }
}
}
The whole code is on gist https://gist.github.com/gandarez/c2c5b2b27dbaf62a0d634253529bcb59
There was a couple of mistakes in the OP's code.
With the snippet provided by @mabu and the code I found on http://www.briangrinstead.com/blog/multipart-form-post-in-c, here's a *functional** Code Block to Upload attachment to Jira.
public bool AddAttachments(string issueKey, IEnumerable<string> filePaths)
{
string restUrl = Jira.FormatRestUrl(m_JiraId, true);
string issueLinkUrl = String.Format("{0}/issue/{1}/attachments", restUrl, issueKey);
var filesToUpload = new List<FileInfo>();
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<FileInfo> 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();
}
}
}
I really didn't want to deal with all that boundary
stuff, so here's my shot at it. This works against Confluence whose API looks identical to Jira.
Thanks to Michael Teper at ASP.NET WebApi: how to perform a multipart post with file upload using WebApi HttpClient and Jeff Caron (above).
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);
}
}