Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VSO API Work Item PATCH giving 400 Bad Request

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);
    }


}
like image 917
Papa Burgundy Avatar asked Oct 25 '25 05:10

Papa Burgundy


1 Answers

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?

like image 145
Tim Avatar answered Oct 26 '25 18:10

Tim



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!