3
votes

I'm working with the Visual Studio Online REST API and can seem to get everything to work except creating a work item. This is not an on premise install. I follow this example and send a PATCH but receive a 400 Bad Request error. VSO Create Work Item

Per fiddler, this is my raw request:

    PATCH https://xxx.visualstudio.com/defaultcollection/myproject/_apis/wit/workitems/$Task?api-version=1.0 HTTP/1.1
Accept: application/json
Authorization: Basic RmI3etc_etc_etc==
Content-Type: application/json-patch+json; charset=utf-8
Host: xxx.visualstudio.com
Content-Length: 101
Expect: 100-continue
Connection: Keep-Alive

{"op":"add","path":"/fields/System.Title","value":"JavaScript implementation for Microsoft Account"}

And the response I get back is 400 Bad Request:

{"$id":"1","innerException":null,"message":"You must pass a valid patch document in the body of the request.","typeName":"Microsoft.VisualStudio.Services.Common.VssPropertyValidationException, Microsoft.VisualStudio.Services.Common, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03ftoken0a3a","typeKey":"VssPropertyValidationException","errorCode":0,"eventId":3000}

I'm not sure why it is saying the patch document is invalid.

UPDATE: Per request, just sharing some more of the code. I tinkered around with my own library. Here is what I've made to easily add a Work Item to a project (product backlog, bug, etc)

public void AddWorkItem(VSOWorkItem workItem, string project)
    {
        Project = project;

        using (HttpClient client = new HttpClient())
        {
            client.DefaultRequestHeaders.Accept.Add(
            new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

            //Set alternate credentials
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
                Convert.ToBase64String(
                    System.Text.ASCIIEncoding.ASCII.GetBytes(
                        string.Format("{0}:{1}", UserName, Password))));

            var workItems = new List<VSOFieldPatch>();
            workItems.Add(new VSOFieldPatch() { Op = "add", Path = "/fields/" + VSOWorkItemFieldName.Title, Value = workItem.Title });
            workItems.Add(new VSOFieldPatch() { Op = "add", Path = "/fields/" + VSOWorkItemFieldName.Description, Value = workItem.Description });

            if (!string.IsNullOrEmpty(workItem.Tags))
                workItems.Add(new VSOFieldPatch() { Op = "add", Path = "/fields/" + VSOWorkItemFieldName.Tags, Value = workItem.Tags });

            var resp = AddWorkItemAsync(client, workItems, BaseProjectUrl + "wit/workitems/$" + workItem.WorkItemType.ToString());
        }

    }


 private async Task<String> AddWorkItemAsync(HttpClient client,
                                      IEnumerable<VSOFieldPatch> data,
                                      String apiUrl)
    {
        var responseBody = String.Empty;

        var temp = JsonConvert.SerializeObject(data);

        var content = new StringContent(
            JsonConvert.SerializeObject(data),
            Encoding.UTF8,
            "application/json-patch+json");

        try
        {
            using (HttpResponseMessage response = client.PatchAsync(apiUrl + ApiVersion, content).Result)
            {
                response.EnsureSuccessStatusCode();
                responseBody = await response.Content.ReadAsStringAsync();
            }
        }
        catch (Exception ex)
        {

        }

        return responseBody;
    }

And this is my PATCH extension:

public static class HttpClientExtensions
{

    public static Task<HttpResponseMessage> PatchAsync(this HttpClient client, string requestUri, HttpContent content)
    {
        HttpRequestMessage request = new HttpRequestMessage
        {
            Method = new HttpMethod("PATCH"),
            RequestUri = new Uri(client.BaseAddress + requestUri),
            Content = content,
        };

        return client.SendAsync(request);
    }


}
2
Hi sir , could you post the full sample code for my reference ? I am using JavascriptSerializer to send a Patch request. - Ace McCloud
@PrasaanthNeelakandan see if that helps - Papa Burgundy
I have almost the exact same code that doesn't work ... stackoverflow.com/questions/36023821/… - Ace McCloud
that question i tried the first answer as well.. I used POSTMAN to check the Patch request and it returned that "The requested resource does not support http method 'PATCH' " - Ace McCloud
I am trying to update a field and not create w work item though - Ace McCloud

2 Answers

9
votes

All the examples look like they're sending an array of operations, not just a single operation. I don't know if that's a requirement or not. But perhaps it is expecting the body of the PATCH to be an array.

Could you try sending:

[{"op":"add","path":"/fields/System.Title","value":"JavaScript implementation for Microsoft Account"}]

and see if it works?

1
votes

Changing application/json to application/json-patch+json seemed to do the trick for me.