Reputation: 389
I am in the process of creating a simple winform application, which can create new bug items into my Visual Studio Team Services agile workflow, using the API provided. The API Documentation
Currently it can create a new bug, with title, tags and description.
I want to be able to add file attachments, but for some reason this is not working.
The code to create the bug is below
private static void createInitailItemPostObject()
{
AddUpdateProp("/fields/System.Title", newTaskItem.Title);
AddUpdateProp("/fields/System.Tags", newTaskItem.Tags);
AddUpdateProp("/fields/System.Description", newTaskItem.Description);
AddUpdateProp("/fields/System.History", "Upload first file");
}
private static void AddUpdateProp( string field, string value)
{
DataObjectsProject.VSOJasonWorkItemPostData wiPostData = new DataObjectsProject.VSOJasonWorkItemPostData();
wiPostData.op = "add";
wiPostData.path = field;
wiPostData.value = value;
wiPostDataArr.Add(wiPostData);
}
The JSon call is done with the below code
public static async void Post(string url, System.Net.Http.HttpContent wiPostDataContent, string returnType, JSONReturnCallBack callBack)
{
string responseString = String.Empty;
try
{
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Basic",Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", username, password))));
using (System.Net.Http.HttpResponseMessage response = client.PostAsync(url, wiPostDataContent).Result)
{
response.EnsureSuccessStatusCode();
string ResponseContent = await response.Content.ReadAsStringAsync();
responseString = ResponseContent;
}
}
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
Console.ReadLine();
}
callBack(responseString,returnType);
}
To add an attachment I can't seem to get it to convert the below code to work like my current code.
function readBlob() {
var files = document.getElementById('fileselect').files;
if (!files.length) {
alert('Please select a file!');
return;
}
var file = files[0];
var filename = file.name;
var reader = new FileReader();
reader.onloadend = function (evt) {
if (evt.target.readyState == FileReader.DONE) {
// Post file content to server
$.ajax({
url: "http://fabrikam.visualstudio.com/DefaultCollection/_apis/wit/attachments?filename=" + filename + "&api-version=1.0",
data: evt.target.result,
processData: false,
contentType: "application/json",
type: "POST"
});
}
};
reader.readAsArrayBuffer(file);
}
Has anyone else been able to do this?
The URL I am using is the below url to call the API
"https://[ACCOUNT].visualstudio.com/DefaultCollection/[Project]/_apis/wit/attachments?fileName=Test&api-version=1.0"
Upvotes: 4
Views: 4100
Reputation: 43
Below program will create a Bug in VSO and also attach an attachment in the bug.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using Logger;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using Microsoft.VisualStudio.Services.WebApi.Patch;
using Microsoft.VisualStudio.Services.WebApi;
using System.Net.Http.Headers;
using System.Net.Http;
using Newtonsoft.Json;
using System.IO;
using System.Collections;
using Newtonsoft.Json.Linq;
namespace CreateABugInVSOProgrammatically
{
static class ReportBug
{
static string _uri;
static string _personalAccessToken;
static string _project;
static string PathOfAttachment;
public static List<Params> ListParams;
static ReportBug()
{
_uri = ConfigurationManager.AppSettings["DynamicsUrl"];
_personalAccessToken = GetDecodedToken(ConfigurationManager.AppSettings["PAT"]);
_project = ConfigurationManager.AppSettings["ProjectName"];
}
private static List<Params> GetAllField(Fields fields)
{
List<Params> list = new List<Params>();
list.Add(new Params() { Path = "/fields/System.Title", Value = fields.Title });
list.Add(new Params() { Path = "/fields/Microsoft.VSTS.TCM.ReproSteps", Value = fields.ReproSteps });
list.Add(new Params() { Path = "/fields/Microsoft.VSTS.Common.Priority", Value = fields.Priority });
list.Add(new Params() { Path = "/fields/Microsoft.VSTS.Common.Severity", Value = fields.Severity });
list.Add(new Params() { Path = "/fields/Microsoft.VSTS.Common.Issue", Value = fields.Issue });
list.Add(new Params() { Path = "/fields/Microsoft.VSTS.MPT.Source", Value = fields.Source });
list.Add(new Params() { Path = "/fields/System.State", Value = fields.State });
list.Add(new Params() { Path = "/fields/Microsoft.VSTS.Common.HowFoundCategory", Value = fields.HowFoundCategory });
list.Add(new Params() { Path = "/fields/Microsoft.VSTS.Common.Regression", Value = fields.Regression });
list.Add(new Params() { Path = "/fields/System.AttachedFileCount", Value = fields.AttachedFileCount });
return list;
}
public static WorkItem CreateBugInVSO(IWebDriver driver, Fields fields)
{
try
{
PathOfAttachment = ScreenShotCapture.CaptureScreenShotOfCurrentBrowser(driver ,fields.PathOfFile);
ListParams.AddRange(GetAllField(fields));
Uri uri = new Uri(_uri);
string personalAccessToken = _personalAccessToken;
string project = _project;
VssBasicCredential credentials = new VssBasicCredential("", _personalAccessToken);
AttachmentReference attachment = UploadAttachment(uri, credentials);
ListParams.Add(new Params()
{
Path = "/relations/-",
Value = new
{
rel = "AttachedFile",
url = attachment.Url,
attributes = new { comment = fields.Comments }
}
});
JsonPatchDocument patchDocument = new JsonPatchDocument();
//add fields and their values to your patch document
foreach (var item in ListParams)
{
patchDocument.Add(
new JsonPatchOperation()
{
Operation = Operation.Add,
Path = item.Path,
Value = item.Value,
}
);
}
VssConnection connection = new VssConnection(uri, credentials);
WorkItemTrackingHttpClient workItemTrackingHttpClient = connection.GetClient<WorkItemTrackingHttpClient>();
WorkItem result = workItemTrackingHttpClient.CreateWorkItemAsync(patchDocument, project, "Bug").Result;
return result;
}
catch (AggregateException ex)
{
Log.Logger.Error("Error occurred while Creating bug in VSO" + ex);
return null;
}
}
// This method will upload attachment and return url for file and Id
private static AttachmentReference UploadAttachment(Uri uri, VssBasicCredential credentials)
{
try
{
VssConnection _tpc = new VssConnection(uri, credentials);
WorkItemTrackingHttpClient workItemTrackingHttpClient = _tpc.GetClient<WorkItemTrackingHttpClient>();
AttachmentReference attachment = workItemTrackingHttpClient.CreateAttachmentAsync(PathOfAttachment).Result;
// Save the attachment ID for the "download" sample call later
return attachment;
}
catch (Exception ex)
{
Log.Logger.Error("Error occurred while Attaching Attachment in bug" + ex);
return null;
}
}
}
}
public class Params
{
public string Path { get; set; }
public object Value { get; set; }
}
//This class contain all the fields that are mandatory to create a bug
public class Fields
{
public string Title { get; set; }
public string Priority { get; set; }
public string ReproSteps { get; set; }
public string Severity { get; set; }
public string Issue { get; set; }
public string Source { get; set; }
public string State { get; set; }
public string HowFoundCategory { get; set; }
public string Regression { get; set; }
public int AttachedFileCount { get; set; }
public string Comments { get; internal set; }
public string PathOfFile { get; internal set; }
}
Upvotes: 4
Reputation: 26
As you can see in the example code, you don't need to put the project in the URL for the API call. Try doing it with the following url:
Upvotes: 1