【问题标题】:How to programmatically download attachments in Azure DevOps?如何以编程方式下载 Azure DevOps 中的附件?
【发布时间】:2018-05-01 15:42:29
【问题描述】:

我正在尝试使用从 Nuget 下载的 TeamFoundation/VisualStudio C# API 以编程方式从 VSTS 中的用户故事下载 90 多个附件。我试图使用这个例子:https://intellitect.com/downloading-attachments-from-tfs/

但是,该代码似乎已过时。我似乎找不到文章中提到的这些确切软件包:nuget-bot.Microsoft.TeamFoundation.Client nuget-bot.Microsoft.TeamFoundation.WorkItemTracking.Client

但是,我下载了 TFS 包,例如 Microsoft.TeamFoundationServer.Client 和 Microsoft.TeamFoundationServer.ExtendedClient,但 WorkItem 类似乎不再有附件。有人知道我在哪里可以找到 Attachments 属性吗?我在 Visual Studio 中浏览了对象浏览器,但找不到它。或者您能否建议一种替代解决方案来从工作项中获取附件?谢谢。

【问题讨论】:

  • 如果Attachments 属性消失了,我不知道解决方案,但一种解决方法是使用 REST 客户端直接调用 API。 Get the work item 然后get the attachments
  • 谢谢丹。我以前研究过这个,但我不知道如何检索附件 ID。 WorkItem 属性只为您提供工作项标题等内容。我希望能够遍历工作项中的所有附件并下载它们。

标签: c# azure-devops


【解决方案1】:

WebClient 无法正确向 VSTS 进行身份验证。而不是使用 WebClient 下载文件,您可以使用 WorkItemServer.DownloadFile()方法在 Microsoft.TeamFoundation.WorkItemTracking.Proxy下载 文件。详情请见this thread

您可以使用以下示例下载特定工作项的附件:

注意:安装nuget包Microsoft.TeamFoundationServer.ExtendedClient

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Proxy;
using System;
using System.IO;

namespace VSTS_DownloadWITAttachment
{
    class Program
    {
        static void Main(string[] args)
        {
            TfsTeamProjectCollection ttpc = new TfsTeamProjectCollection(new Uri("https://account.visualstudio.com/"));
            ttpc.EnsureAuthenticated();
            WorkItemStore wistore = ttpc.GetService<WorkItemStore>();
            WorkItem wi = wistore.GetWorkItem(94);
            WorkItemServer wiserver = ttpc.GetService<WorkItemServer>();
            string tmppath = wiserver.DownloadFile(wi.Attachments[0].Id); //Change the number to download other attachments if there are more then one attachments for the specific work item. e.g: [1] to download the second one.
            string filename = string.Format("D:\\WITAttachments\\{0}-{1}", wi.Fields["ID"].Value, wi.Attachments[0].Name);
            File.Copy(tmppath, filename);
        }
    }
}

然后您可以尝试查询工作项并为每个工作项循环下载附件。详情请见Fetch work items with queries programatically in VSTS

以下示例供您参考:

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Proxy;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;

namespace DownloadWITAttachments
{
    class Program
    {
        static void Main(string[] args)
        {
            Uri uri = new Uri("https://account.visualstudio.com");
            string PAT = "xxxxxxxxxxxx";
            string project = "ProjectName";

            VssBasicCredential credentials = new VssBasicCredential("", PAT);

            //create a wiql object and build our query
            Wiql wiql = new Wiql()
            {
                Query = "Select * " +
                        "From WorkItems " +
                        "Where [Work Item Type] = 'User Story' " +
                        "And [System.TeamProject] = '" + project + "' " +
                        "And [System.State] <> 'Closed' " +
                        "And [System.AttachedFileCount] > 0 " +
                        "Order By [State] Asc, [Changed Date] Desc"
            };

            //create instance of work item tracking http client
            using (WorkItemTrackingHttpClient workItemTrackingHttpClient = new WorkItemTrackingHttpClient(uri, credentials))
            {
                //execute the query to get the list of work items in the results
                WorkItemQueryResult workItemQueryResult = workItemTrackingHttpClient.QueryByWiqlAsync(wiql).Result;

                if (workItemQueryResult.WorkItems.Count() != 0)
                {
                    //Download the first attachment for each work item.
                    foreach (var item in workItemQueryResult.WorkItems)
                    {
                        TfsTeamProjectCollection ttpc = new TfsTeamProjectCollection(uri);
                        ttpc.EnsureAuthenticated();
                        WorkItemStore wistore = ttpc.GetService<WorkItemStore>();
                        Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem wi = wistore.GetWorkItem(item.Id);
                        WorkItemServer wiserver = ttpc.GetService<WorkItemServer>();                       
                        string tmppath = wiserver.DownloadFile(wi.Attachments[0].Id);
                        string filename = string.Format("D:\\temp\\vsts\\{0}-{1}", wi.Fields["ID"].Value, wi.Attachments[0].Name);
                        File.Copy(tmppath, filename);
                    }
                }
            }
        }
    }
}

【讨论】:

  • 谢谢安迪,但我确实安装了 Nuget 包,但在下面看不到这些。我有最新版本:15.132.0-preview。你用的是什么版本? Microsoft.TeamFoundation.Client;使用 Microsoft.TeamFoundation.WorkItemTracking.Client;使用 Microsoft.TeamFoundation.WorkItemTracking.Proxy;
  • @ray500 我安装了-Version 15.112.1,你可以试试看:nuget.org/packages/…
  • 谢谢安迪。我在那里看到它,但我希望微软不会删除它们。我提到的预发行版没有它们。该解决方案有效!
【解决方案2】:

如果您还没有用于与 API 交互的访问令牌,请生成一个。

进行 API 调用以获取扩展的工作项信息。请注意 $expand=all 参数以检索所有项目详细信息。

GET https://{account}.visualstudio.com/{project}/_apis/wit/workitems/115258?api-version=4.1&$expand=all

响应应该看起来像这样(如果项目有附件)。

{
    "id": 115258,
    "rev": 4,
    "fields": {
        "System.Id": 115258,
        "System.AreaId": 2643
        ...and so on...
    },
    "relations": [
        {
            "rel": "AttachedFile",
            "url": "https://{account}.visualstudio.com/d6c4b828-0f7e-4b69-a356-a92c0ec3cd07/_apis/wit/attachments/5682f031-4b09-478c-8042-0d2a998905e4",
            "attributes": {
                "authorizedDate": "2018-04-30T19:34:09.763Z",
                "id": 2015371,
                "resourceCreatedDate": "2018-04-30T19:34:07.873Z",
                "resourceModifiedDate": "2018-04-30T19:32:16.057Z",
                "revisedDate": "9999-01-01T00:00:00Z",
                "resourceSize": 47104,
                "name": "file.jpg"
            }
        }
    ]
}

遍历relations,其中relAttachedFile,并调用url获取附件内容。

GET https://{account}.visualstudio.com/d6c4b828-0f7e-4b69-a356-a92c0ec3cd07/_apis/wit/attachments/5682f031-4b09-478c-8042-0d2a998905e4

来源:

【讨论】:

  • 谢谢丹。我找到了这个并在 Visual Studio 中尝试了它,但我无法让 HTTPResponse 给我包含数据的文件。所以我尝试了安迪的解决方案,它奏效了。
  • 为什么是 POST?获取附件记录为 GET。
  • 你是对的@Matthieu,应该是GET。已更新。
猜你喜欢
  • 2019-06-20
  • 1970-01-01
  • 2018-11-09
  • 1970-01-01
  • 2012-01-10
  • 2020-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多