4

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"

Esther Fan - MSFT
  • 8,276
  • 4
  • 27
  • 25
Chris Cooper
  • 389
  • 3
  • 16

2 Answers2

4

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; }
}
  • Hi thanks this has been resolved I’ve created an app that we us now. My code is on GitHub and you can download it the compiled app to us. Thanks tho – Chris Cooper Aug 03 '18 at 11:32
1

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:

"https://[ACCOUNT].visualstudio.com/DefaultCollection/_apis/wit/attachments?fileName=Test&api-version=1.0"

LaMu
  • 26
  • 3
  • I've been looking at that for hours. The other calls need the Project, but I'm guessing the Attached documents do not get stored against the project. The next stage, you do then link the attachment with the task,bug. Thanks – Chris Cooper Jun 14 '16 at 08:31