In a custom C# Winforms app, I'm using the Azure DevOps REST API Update Comments call to update work item comments using async/await
My call to UpdateComment_Async
is in a tight loop designed to submit all update comment requests for a single work item and then process each comment update as it completes.
Following is a mix of p-code and C# for (almost) working code. In the case where there are 2 (or more) comments to update, the first update returns HttpResponseMessage.Status 200 (success), but the second update submitted returns HttpResponseMessage.Status 409 "Conflict". I assume that ADS has the work item locked for the first update, and so the 2nd update fails with the 409. I think I proved this by sleeping the thread for 5 seconds after the call to UpdateComment_Async. With the sleep in place, both updates work.
Is there a way to manage the series of calls to UpdateComment_Async so that subsequent calls aren't done until the previous one is complete?
CODE
// get comment(s) for one work item .......
foreach (comment in workItem)
{
newCommentText = "new comment text blah-blah-blah";
Task<Tuple<string, string, HttpResponseMessage>> updateCommentTask = UpdateComment_Async(projectUrl, workItem.Id.ToString(), comment.Id.ToString(), newCommentText);
// I put a thread.sleep(5000) right here
updateCommentTaskList.Add(updateCommentTask);
}
// Process update comments tasks as they complete
while (updateCommentTaskList.Count > 0)
{
Task<Tuple<string, string, HttpResponseMessage>> finishedUpdateCommentTask = await Task.WhenAny(updateCommentTaskList);
// Get Results
Tuple<string, string, HttpResponseMessage> updateCommentTaskResult = finishedUpdateCommentTask.Result;
// process updateCommentTaskResult
// etc
// etc
// etc
updateCommentTaskList.Remove(finishedUpdateCommentTask);
}
//*******************************
public async Task<Tuple<string, string, HttpResponseMessage>> UpdateComment_Async(string projectUrl, string workItemId, string commentId, string commentNumber, string newCommentText)
{
HttpResponseMessage responseResult = null;
#region MAKE JSON REQUEST BODY
IList<ClsUpdateComment> updateFieldJsonList = new List<ClsUpdateComment>();
updateFieldJsonList.Clear();
// Note: This code works but is not in compliance with MS docs on 2 counts.
//
// 1) The MS docs on comment update say that the body should look like fig 1.
// The only I could do this was to create a new ClsUpdateComment and then add it to
// List<ClsUpdateComment>. Adding the ClsUpdateComment object to a list causes the [ ]
// to be created when the list is serialized. To make this work, I had to serialize
// just the ClsUpdateComment object so that when serialzed, it ends up looking like Fig 2 (no brackets)
//
// 2) application/json-patch+json causes error 415 - unsupported media type to occur. application/json
// works.
/*
Fig 1
[
{
"text": "Moving to the right area path - Fabrikam-Git"
}
]
Fig 2
{
"text": "Moving to the right area path - Fabrikam-Git"
}
*/
ClsUpdateComment updateFieldJson = new ClsUpdateComment
{
Text = $"{newCommentText}"
};
updateFieldJsonList.Add(updateFieldJson);
#endregion MAKE JSON REQUEST BODY
#region SUBMIT UPDATE REQUEST
string request = $"{projectUrl}/_apis/wit/workitems/{workItemId}/comments/{commentId}?api-version=5.1-preview.3";
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
{
StringEscapeHandling = StringEscapeHandling.EscapeHtml,
};
string updateFieldJsonSerialized = JsonConvert.SerializeObject(updateFieldJson, Formatting.None, jsonSerializerSettings);
using (HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true, ClientCertificateOptions = ClientCertificateOption.Manual }))
{
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(new HttpMethod("PATCH"), request)
{
Content = new StringContent(updateFieldJsonSerialized, Encoding.UTF8, "application/json")
};
using (responseResult = await client.SendAsync(httpRequestMessage))
{
// don't need Content, just the HttpResponseMessage
// //string content = await responseResult.Content.ReadAsStringAsync();
}
}
#endregion SUBMIT UPDATE REQUEST
return Tuple.Create(workItemId, commentNumber, responseResult);
}
It's not an answer, but after trying to do mass updates of comments using the REST API in various ways, I've come to the conclusion that it simply doesn't support mass updates of comments