2
votes

I'm trying to create a workitem in Azure DevOps using client libraries and using OAuth as authentication mechanism.

It works fine on my local machine (when I debug it locally), but throws exceptions whenever deployed on cloud(in my case Azure App service).

public string CreateWorkItemDemo(string accesstoken)
    {
        try
        {
            Uri _uri = new Uri("https://xyz.visualstudio.com");
            JsonPatchDocument patchDocument = new JsonPatchDocument();
            string project = "abcproject";
            patchDocument.Add(
                new JsonPatchOperation()
                {
                    Operation = Operation.Add,
                    Path = "/fields/System.Title",
                    Value = "Test item created through token two"
                });
            patchDocument.Add(
                new JsonPatchOperation()
                {
                    Operation = Operation.Add,
                    Path = "/fields/System.AreaPath",
                    Value = string.Format("{0}", project)
                });
            try
            {
                VssConnection connection = new VssConnection(_uri, new VssOAuthAccessTokenCredential(accesstoken));
                WorkItemTrackingHttpClient workItemTrackingHttpClient = connection.GetClient<WorkItemTrackingHttpClient>();
                try
                {
                    var result = workItemTrackingHttpClient.CreateWorkItemAsync(patchDocument, project, "Bug").Result; //This line of code throws exception
                    return result.Id.Value.ToString();
                }
                catch (Exception ex)
                {
                   //The exceptions is logged from here.
                }
            }
            catch (Exception ex)
            {
                 //Exception messages here
            }
        }
        catch (Exception exception)
        {
               //Exception messages here
        }

The exception that it is throwing is:

One or more errors occurred. ex.stacktrace at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) at System.Threading.Tasks.Task1.GetResultCore(Boolean waitCompletionNotification) at System.Threading.Tasks.Task1.get_Result()

This method is called directly from a link and the accesstoken is passed along with it. Earlier I was calling this method through ajax call as I thought maybe ajax calls don't wait for async. But it throwed the same exception.

Then I changed my method to async/await and called it through a link. Here is the code:

public async Task<string> CreateItem(string accesstoken)
    {
        string _uri = "https://xyz.visualstudio.com";
        Uri uri = new Uri(_uri);
        string project = "abcproject";
        JsonPatchDocument patchDocument = new JsonPatchDocument();
        patchDocument.Add(
            new JsonPatchOperation()
            {
                Operation = Operation.Add,
                Path = "/fields/System.Title",
                Value = "Test item created through code seven"
            });
        patchDocument.Add(
            new JsonPatchOperation()
            {
                Operation = Operation.Add,
                Path = "/fields/System.AreaPath",
                Value = string.Format("{0}", project)
            });
        try
        {
            VssConnection connection = new VssConnection(uri, new VssOAuthAccessTokenCredential(accesstoken));
            WorkItemTrackingHttpClient workItemTrackingHttpClient = connection.GetClient<WorkItemTrackingHttpClient>();
            try
            {
                var response = await workItemTrackingHttpClient.CreateWorkItemAsync(patchDocument, project, "Bug");

                return "Successfully created bug with Id" + response.Id.Value.ToString();
            }
            catch (Exception ex)
            {
                //Exceptions are logging here
                return ex.Message + " ," + ex.StackTrace + " One here";
            }
        }
        catch (Exception ex)
        {
            return ex.Message + " ," + ex.StackTrace + " 2 here";
        }
    }

Here I'm getting this kind of exception and with the last line:

d__52.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.d__50.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.d__471.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.d__281.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

You must pass a valid patch document in the body of the request. , at Microsoft.VisualStudio.Services.WebApi.VssHttpClientBase.

Since I'm using OAuth mechanism, the accesstokens are generated only in my cloud app. So to run it locally, I've created a separate Asp.net web application and running it locally by passing the access token generated from my cloud app.

And I can't emphasize it enough that both the methods are running perfectly fine when I ran it locally multiple times.

I'm strucked badly with this, and since I'm a little bit newbie to this programming world, any help with a little bit detail will be much appreciated

3

3 Answers

0
votes

The similar question was here: You must pass a valid patch document in the body of the request. Used WorkItemTrackingHttpClient

This is then a Bug of the stable version, so you have to use a preview version

Try to update to preview version your client libs.

0
votes

Edit:

I seriously don't know how, but when I deployed my above code on Azure cloud service, it works. But it still shows the exceptions when I run it on Azure App service. Maybe the Azure App service that I was using came under a free plan (without any Cores), so that might be the case. However please note that HttpClient worked in both the cases. Hope this answer can save someone's time.

This code works fine. Here instead of using WorkItemHttpClient, I'm using HttpClient.


public async Task<string> CreateWorkItemUsingHttpClient(string accesstoken)
    {
        try
        {
            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json-patch+json"));
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accesstoken);
            WorkItemPostData wiPostData = new WorkItemPostData();
            wiPostData.op = "add";
            wiPostData.path = "/fields/System.Title";
            wiPostData.value = "Workitem created through cloud";
            List<WorkItemPostData> wiPostDataArr = new List<WorkItemPostData> { wiPostData };
            string wiPostDataString = JsonConvert.SerializeObject(wiPostDataArr);
            HttpContent wiPostDataContent = new StringContent(wiPostDataString, Encoding.UTF8, "application/json-patch+json");
            string url = "https://dev.azure.com/xyz/abcproject/_apis/wit/workitems/$Bug?api-version=5.0";
            try
            {
                HttpResponseMessage response = client.PatchAsync(url, wiPostDataContent).Result;
                try
                {
                    if (response.IsSuccessStatusCode)
                    {
                        response.EnsureSuccessStatusCode();
                        string responseContent = await response.Content.ReadAsStringAsync();
                        return responseContent;
                    }
                    else
                    {
                        return "Success code returned false";
                    }
                }
                catch(Exception ex)
                {
                    return "One " +ex.Message + " " + ex.StackTrace;
                }
            }
            catch(Exception ex)
            {
                return "Two " +ex.Message + " " + ex.StackTrace;
            }
        }
        catch(Exception ex)
        {
            return "Three " +ex.Message + " " + ex.StackTrace;
        }
    }

This code works fine in local as well as when deployed on cloud. I don't know why WorkItemHttpClient isn't working on cloud and giving exceptions related to threading and patching eventhough it's working fine locally. I'm just making a layman guess that maybe WorkItemHttpClient isn't powerful enough as that of HttpClient and hence it's not able to create workitems when deployed on cloud as it has to do it faster. But this is just a non technical guess.

Anyways I posted this answer just so that some other person who might face the same problem can refer this solution if they want.

0
votes

Followed steps as in documentation,

https://docs.microsoft.com/es-es/azure/devops/integrate/quickstarts/create-bug-quickstart?view=azure-devops&viewFallbackFrom=vsts

Just one change,

Instead of

WorkItem result = workItemTrackingHttpClient.CreateWorkItemAsync(patchDocument, project, "Bug").Result;

New Code

WorkItem result = workItemTrackingHttpClient.CreateWorkItemAsync(patchDocument, project, "Issue").Result;