Как программно загрузить вложения в Azure DevOps?

Я пытаюсь программно загрузить более 90 вложений из пользовательской истории в VSTS, используя TeamFoundation / VisualStudio C# API, который я загрузил с Nuget. Я пытался использовать этот пример: 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 исчезло, но одним из способов решения проблемы было бы вызов API напрямую с помощью клиента REST. Получите рабочий элемент, а затем получить вложения.

Dan Wilson 01.05.2018 17:51

Спасибо, Дэн. Я уже разбирался в этом раньше, но не понимаю, как получить идентификатор вложения. Свойства WorkItem дают вам только такие вещи, как заголовок рабочего элемента и т. д. Я хочу иметь возможность просматривать все вложения в рабочем элементе и загружать их.

ray500 01.05.2018 20:14
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
2
2 260
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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, где rel - это AttachedFile, и вызовите url, чтобы получить содержимое вложения.

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

Источники:

Спасибо, Дэн. Я нашел это и попробовал в Visual Studio, но не смог получить HTTPResponse, чтобы передать мне файл с данными. Итак, я попробовал решение Энди, и оно сработало.

ray500 02.05.2018 23:04

Почему ПОЧТА? Получить вложения задокументировано как GET.

Matthieu 13.06.2019 22:33

Вы правы, @Matthieu, это должен быть GET. Обновлено.

Dan Wilson 14.06.2019 13:39
Ответ принят как подходящий

WebClient cannot authenticate to VSTS correctly. Instead of using WebClient to download the file, you can use WorkItemServer.DownloadFile()method in Microsoft.TeamFoundation.WorkItemTracking.Proxy to download the file. See this thread for details.

Вы можете использовать приведенный ниже образец, чтобы загрузить вложение для определенного рабочего элемента:

Примечание. Установите пакет 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);
        }
    }
}

Затем вы можете попытаться запросить рабочие элементы и загрузить вложения в цикле для каждого из них. Подробнее см. Получение рабочих элементов с запросами программно в 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 02.05.2018 19:17

@ ray500 Я установил -Version 15.112.1, вы можете попробовать: nuget.org/packages/…

Andy Li-MSFT 03.05.2018 04:28

Спасибо, Энди. Я вижу это там, но надеюсь, что Microsoft их не удалит. На упомянутом мною пререлизе их нет. Решение работает !!

ray500 04.05.2018 23:35

Другие вопросы по теме