通过API在团队服务中创建工作项

3
我正在尝试创建一个 Web 应用程序(托管在 Azure 上),使客户能够向我们的团队服务页面提交工作项。基本上是一个支持票据页面,这样他们就不必一直打电话解释他们的积压工作。
下面是我创建工作项的类和方法,遵循 Microsoft 的示例代码,并对隐私进行了一些明显的更改。这个方法由按钮点击触发,但到目前为止,我无法创建任何工作项。
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;

 namespace customapp
 {
  public class CreateWorkItem
  {


    public void CreateWorkItemMethod()
    {

        string personalAccessToken = "xxxxxxxxx";
        string credentials = Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "xxx", personalAccessToken)));

        Object[] patchDocument = new Object[1];

        patchDocument[0] = new { op = "add", path = "/fields/System.Title", value = "Test" };


        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);


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

            var method = new HttpMethod("PATCH");
            var request = new HttpRequestMessage(method, "https://example.visualstudio.com/exampleproject/_apis/wit/workitems/$Support&20Ticket?api-version=1.0") { Content = patchValue };
            var response = client.SendAsync(request).Result;


            if (response.IsSuccessStatusCode)
            {
               var result = response.Content.ReadAsStringAsync().Result;

            }

 }}}} 

在PATCH的URL中,我使用了团队项目的ID(代替下面所示的/exampleproject)。我们的网站设置了一个总体项目,让我们称其为“Master”,里面有一个针对每个客户的团队项目,例如“ClientProject”。因此,基本上我想在Master->ClientProject->Backlog/Board中创建一个“支持工单”工作项。

似乎出现了一个错误,它不知道该去哪里。在 HttpRequestMessage 中,我为 Support 和 Ticket 之间的空格添加了 %20,但错误显示它不是工作类型。所以我尝试使用 "Bug" 替代,这个方法有效,并且 vsts 上的统计页面显示已创建了一个工作项,但我无法找到它的位置。 - user8115978
工作项类型是否命名为Support Ticket或*$Support Ticket*?您的代码试图创建一个$Support&20Ticket,这应该改为Support%20Ticket。请注意,没有前导美元符号,并且空格已正确转义为%20而不是&20 - Daniel Mann
@DanielMann,你的发现很好,&应该改成%。我现在可以创建工作项了,但它们被发送到主项目文件夹的积压中,而不是其中的团队项目。将“path ="/fields/System.AreaPath",value ="Master\teamproject"”添加到有效载荷中无效,并显示错误“为工作项给定了无效的树名称”。 - user8115978
@M.W. 你对于团队项目结构的解释有些令人困惑。VSTS每个账户只支持一个团队项目集合,而你已经在REST URL中指定了团队项目。因此,你只需要指定相对于团队项目根目录的区域路径。术语“团队项目”具有非常具体的含义,我怀疑你正在错误使用它。 - Daniel Mann
@DanielMann 为了更好地解释,整个集合是我所说的主集合。在这个集合内应该有一个区域路径(我认为?)为每个客户端,这样他们就可以拥有自己的待办事项和团队成员分配。我以为 PATCH 请求 URL 中的“exampleproject”应该是区域路径的名称,但实际上它应该是团队项目(Master)。所以现在我尝试使用“path ="/fields/System.AreaPath",value ="areapathname"”来指定区域路径,但仍然出现“无效的树名称”错误。 - user8115978
显示剩余4条评论
2个回答

5

使用Master\\areapath代替(而不是Master\areapath)。

示例正文:

[
  {
    "op": "add",
    "path": "/fields/System.Title",
    "value": "PBIAPI2"
  },
  {
    "op": "add",
    "path": "/fields/System.AreaPath",
    "value": "Scrum2015\\SharedArea"
  }
]

另一方面,最好使用Microsoft Team Foundation Server Extended Client package的VSTS/TFS API创建工作项。
简单示例代码:
var u = new Uri("https://[account].visualstudio.com");
            VssCredentials c = new VssCredentials(new Microsoft.VisualStudio.Services.Common.VssBasicCredential(string.Empty, "[personal access token]"));
           var connection = new VssConnection(u, c);

var workitemClient = connection.GetClient<WorkItemTrackingHttpClient>();
var workitemtype = "Product Backlog Item";
            string teamProjectName = "Scrum2015";
            var document = new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchDocument();
            document.Add(
    new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation()
    {
        Path = "/fields/Microsoft.VSTS.Common.Discipline",
        Operation = Microsoft.VisualStudio.Services.WebApi.Patch.Operation.Add,
        Value = "development"
    });
            document.Add(
                new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation()
                {
                    Path = "/fields/System.Title",
                    Operation = Microsoft.VisualStudio.Services.WebApi.Patch.Operation.Add,
                    Value = string.Format("{0} {1}", "RESTAPI", 6)
                });
            document.Add(new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation()
            {
                Path = "/fields/System.AreaPath",
                Operation = Microsoft.VisualStudio.Services.WebApi.Patch.Operation.Add,
                Value =string.Format("{0}\\{1}",teamProjectName, "SharedArea")
            });
            document.Add(
                new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation()
                {
                    Path = "/fields/System.AssignedTo",
                    Operation = Microsoft.VisualStudio.Services.WebApi.Patch.Operation.Add,
                    Value = "[user account]"
                });
            document.Add(
                new Microsoft.VisualStudio.Services.WebApi.Patch.Json.JsonPatchOperation()
                {
                    Path = "/fields/System.Description",
                    Operation = Microsoft.VisualStudio.Services.WebApi.Patch.Operation.Add,
                    Value = "destest"
                });
var workitem= workitemClient.CreateWorkItemAsync(document, teamProjectName, workitemtype).Result;

那个运行得非常好,谢谢!TFS Extended Client包有哪些好处? - user8115978
使用起来很方便。 - starian chen-MSFT

3

调用 TFS API 的方法必须使用 POST 请求方式,Uri 格式如下:

https://dev.azure.com/{组织}/{项目}/_apis/wit/workitems/${类型}?api-version=5.0

查看详情请访问:

https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/work%20items/create?view=azure-devops-rest-5.0

以下代码对我很有帮助。

 static void Main(string[] args)
    {
        CreateWorkItem();
    }


    public static void CreateWorkItem()
    {
        string _tokenAccess = "************"; //Click in security and get Token and give full access https://azure.microsoft.com/en-us/services/devops/
        string type = "Bug";
        string organization = "type your organization";
        string proyect = "type your proyect";
        string _UrlServiceCreate = $"https://dev.azure.com/{organization}/{proyect}/_apis/wit/workitems/${type}?api-version=5.0";
        dynamic WorkItem = new List<dynamic>() {
                new
                {
                    op = "add",
                    path = "/fields/System.Title",
                    value = "Sample Bug test"
                }
            };

        var WorkItemValue = new StringContent(JsonConvert.SerializeObject(WorkItem), Encoding.UTF8, "application/json-patch+json");
        var JsonResultWorkItemCreated = HttpPost(_UrlServiceCreate, _tokenAccess, WorkItemValue);
    }


    public static string HttpPost(string urlService, string token, StringContent postValue)
    {
        try
        {
            string request = string.Empty;
            using (HttpClient httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Accept.Clear();
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "", token))));
                using (HttpRequestMessage httpRequestMessage = new HttpRequestMessage(new HttpMethod("POST"), urlService) { Content = postValue })
                {
                    var httpResponseMessage = httpClient.SendAsync(httpRequestMessage).Result;
                    if (httpResponseMessage.IsSuccessStatusCode)
                        request = httpResponseMessage.Content.ReadAsStringAsync().Result;
                }
            }
            return request;
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接