我正在使用 Azure DevOps API 在项目中创建嵌套区域路径。我的代码创建一个子项,然后立即尝试在其下添加一个子项,依此类推,以创建一个多层结构。
我面临的问题是,在创建第一个子项之后,当我尝试创建子项时,API 会抛出错误,指出路径不存在。但是,如果我重新运行代码或稍等一下再试一次,路径就在那里,并且子级会被很好地创建。
Azure DevOps 完全提交新创建的区域路径似乎存在延迟,这导致下一个 API 调用失败,因为它还找不到新添加的父路径。
public async Task<WorkItemClassificationNode> CreateAreaPath(WorkItemTrackingHttpClient client, string projectName, WorkItemClassificationNode currentNode, string areaPath)
{
string[] areaParts = areaPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
string[] fullAreaParts = new string[areaParts.Length + 1];
fullAreaParts[0] = projectName; // Add project name as the root
Array.Copy(areaParts, 0, fullAreaParts, 1, areaParts.Length);
int matchIndex = Array.FindIndex(fullAreaParts, part => part.Equals(currentNode.Name, StringComparison.OrdinalIgnoreCase));
if (matchIndex >= 0)
{
string cleanedPath = CleanePath(currentNode.Path);
string[] remainingParts = fullAreaParts.Skip(matchIndex + 1).ToArray();
foreach (string part in remainingParts)
{
var newNode = new WorkItemClassificationNode()
{
Name = part,
StructureType = TreeNodeStructureType.Area,
};
var resultNode = await client.CreateOrUpdateClassificationNodeAsync(newNode, projectName, TreeStructureGroup.Areas, cleanedPath);
currentNode = resultNode;
cleanedPath += $"/'{part}'";
}
return currentNode;
}
else
{
Console.WriteLine($"Deepest Node '{currentNode.Name}' not found in '{areaPath}'");
return null;
}
}
像这样的 Main()
WorkItemClassificationNode deepestNode = await helper.CreateAreaPath(workItemTrackingClient, projectName2, furthestChild, "Child1/ChildChild/ChildChildChild");
因此,如果我最远的Child是Child1,该函数应该添加ChildChild,然后添加ChildChildChild。
所以第一次调用该方法后,只创建了ChildChild,然后创建ChildChildChild时出现错误。
再次运行该方法后,该方法成功创建了ChildChildChild。所以现在只能向现有节点添加一级子节点。
我添加了一些输出进行检查,对您的代码做了轻微的更改,
ChildChild
和ChildChildChild
分层区域路径已成功创建。
请检查以下脚本:
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.WebApi;
using System.Collections.Generic;
using Microsoft.VisualStudio.Services.Common;
public class AreaPathHelper
{
public async Task<WorkItemClassificationNode> CreateAreaPath(WorkItemTrackingHttpClient client, string projectName, WorkItemClassificationNode currentNode, string areaPath)
{
string[] areaParts = areaPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
string[] fullAreaParts = new string[areaParts.Length + 1];
fullAreaParts[0] = projectName; // Add project name as the root
Array.Copy(areaParts, 0, fullAreaParts, 1, areaParts.Length);
Console.WriteLine("Full Area Parts: " + string.Join(", ", fullAreaParts));
int matchIndex = Array.FindIndex(fullAreaParts, part => part.Equals(currentNode.Name, StringComparison.OrdinalIgnoreCase));
Console.WriteLine("Match Index: " + matchIndex);
if (matchIndex >= 0)
{
string cleanedPath = CleanPath(currentNode.Path);
string[] remainingParts = fullAreaParts.Skip(matchIndex + 1).ToArray();
foreach (string part in remainingParts)
{
var newNode = new WorkItemClassificationNode()
{
Name = part,
StructureType = TreeNodeStructureType.Area,
};
var resultNode = await client.CreateOrUpdateClassificationNodeAsync(newNode, projectName, TreeStructureGroup.Areas, cleanedPath);
currentNode = resultNode;
cleanedPath += $"/{part}";
}
return currentNode;
}
else
{
Console.WriteLine($"Deepest Node '{currentNode.Name}' not found in '{areaPath}'");
return null;
}
}
private string CleanPath(string path)
{
// Implement your path cleaning logic here if needed
return path;
}
}
public class Program
{
public static async Task Main(string[] args)
{
var workItemTrackingClient = new WorkItemTrackingHttpClient(new Uri("https://dev.azure.com/orgname"), new VssBasicCredential(string.Empty, "yourPAT"));
var helper = new AreaPathHelper();
string projectName2 = "project1";
var furthestChild = new WorkItemClassificationNode { Name = "Child1", Path = "Child1" };
WorkItemClassificationNode deepestNode = await helper.CreateAreaPath(workItemTrackingClient, projectName2, furthestChild, "Child1/ChildChild/ChildChildChild");
if (deepestNode != null)
{
Console.WriteLine($"Deepest Node Created: {deepestNode.Name}");
}
}
}
确保将“https://dev.azure.com/orgname”、“yourPAT”、“ProjectName”、节点名称和路径名称分别替换为您的实际值。
我的原来区域路径:
执行的脚本: