Поделиться через


Руководство. Создание клиента REST API

Приложение, использующее REST API, является очень распространенным сценарием. Обычно необходимо создать клиентский код, который приложение может использовать для вызова REST API. В этом руководстве вы узнаете, как автоматически создавать клиент REST API во время сборки с помощью MSBuild. Вы будете использовать NSwag— средство, которое создает клиентский код для REST API.

Полный пример кода доступен в разделе по генерации клиента REST API в репозитории примеров .NET на GitHub.

В примере показан консольное приложение, которое использует общедоступный API Pet Store, который публикует спецификацию OpenAPI.

В этом руководстве предполагается базовое знание терминов MSBuild, таких как задачи, цели, свойства или среды выполнения. За необходимой справочной информацией см. статью «Основные понятия MSBuild».

Если вы хотите запустить средство командной строки в рамках сборки, рекомендуется рассмотреть два подхода. Один из них — использовать задачу MSBuild Exec, которая позволяет запустить средство командной строки и указать его параметры. Другим способом является создание настраиваемой задачи, производной от ToolTask, что обеспечивает более широкий контроль.

Необходимые условия

У вас должно быть представление о понятиях MSBuild, таких как задачи, целевые объекты и свойства. См. основные понятия MSBuild .

В примерах требуется MSBuild, которая установлена с Visual Studio, но также может быть установлена отдельно. См. раздел Скачивание MSBuild безVisual Studio.

Вариант 1: Выполнить задачу

Задача exec просто вызывает указанный процесс с указанными аргументами, ожидает завершения, а затем возвращает true, если процесс завершается успешно, и false, если возникает ошибка.

Генерацию кода NSwag можно осуществить через MSBuild; см. подробности в NSwag.MSBuild.

Полный код находится в папке PetReaderExecTaskExample; вы можете скачать и посмотреть. В этом руководстве вы будете выполнять шаги один за другим и по пути осваивать новые концепции.

  1. Создайте консольное приложение с именем PetReaderExecTaskExample. Используйте .NET 6.0 или более поздней версии.

  2. Создайте другой проект в том же решении: PetShopRestClient (это решение будет содержать созданный клиент в качестве библиотеки). Для этого проекта используйте .NET Standard 2.1. Созданный клиент не компилируется в .NET Standard 2.0.

  3. В проекте PetReaderExecTaskExample создайте, а затем добавьте проектную зависимость к проекту PetShopRestClient.

  4. В проекте PetShopRestClient включите следующие пакеты NuGet:

    • Nswag.MSBuild, который позволяет получить доступ к генератору кода из MSBuild
    • Newtonsoft.Json, необходимый для компиляции созданного клиента
    • System.ComponentModel.Annotations, необходимый для компиляции созданного клиента
  5. В проекте PetShopRestClient добавьте папку (с именем PetShopRestClient) для создания кода и удалите Class1.cs, которая была автоматически создана.

  6. Создайте текстовый файл с именем petshop-openapi-spec.json в корне проекта. Скопируйте спецификацию OpenAPI из здесь и сохраните ее в файле. Рекомендуется скопировать копию спецификации вместо ее чтения онлайн во время сборки. Всегда требуется последовательно воспроизводимая сборка, которая зависит только от входных данных. Использование API напрямую может превратить сборку, которая работает сегодня, в сборку, которая завтра не работает из того же источника. Моментальный снимок, сохраненный на petshop-openapi-spec.json, позволит нам по-прежнему сохранять версию, которая собирается, даже если спецификация изменится.

  7. Затем измените PetShopRestClient.csproj и добавьте целевые объекты MSBuild для создания клиента во время процесса сборки.

    Сначала добавьте некоторые свойства, полезные для создания клиента:

     <PropertyGroup>
         <PetOpenApiSpecLocation>petshop-openapi-spec.json</PetOpenApiSpecLocation>
         <PetClientClassName>PetShopRestClient</PetClientClassName>
         <PetClientNamespace>PetShopRestClient</PetClientNamespace>
         <PetClientOutputDirectory>PetShopRestClient</PetClientOutputDirectory>
     </PropertyGroup>
    

    Добавьте следующие целевые объекты:

     <Target Name="generatePetClient" BeforeTargets="CoreCompile" Inputs="$(PetOpenApiSpecLocation)" Outputs="$(PetClientOutputDirectory)\$(PetClientClassName).cs">
         <Exec Command="$(NSwagExe) openapi2csclient /input:$(PetOpenApiSpecLocation)  /classname:$(PetClientClassName) /namespace:$(PetClientNamespace) /output:$(PetClientOutputDirectory)\$(PetClientClassName).cs" ConsoleToMSBuild="true">
         <Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
       </Exec>
     </Target>
     <Target Name="forceReGenerationOnRebuild" AfterTargets="CoreClean">
        <Delete Files="$(PetClientOutputDirectory)\$(PetClientClassName).cs"></Delete>
     </Target>
    

    Обратите внимание, что этот целевой объект использует атрибуты BeforeTarget и AfterTarget в качестве способа определения порядка сборки. Первый целевой объект, называемый generatePetClient, будет выполнен до выполнения основного целевого объекта компиляции, поэтому источник будет создан до выполнения компилятора. Входные и выходные параметры связаны с инкрементальной сборкой. MSBuild может сравнить метки времени входных файлов с метками времени выходных файлов и определить, следует ли пропускать, создавать или частично перестраивать целевой объект.

    После установки пакета NuGet NSwag.MSBuild в проекте можно использовать переменную $(NSwagExe) в файле .csproj для запуска средства командной строки NSwag в целевом объекте MSBuild. Таким образом, средства можно легко обновить с помощью NuGet. Здесь вы используете задачу Exec MSBuild для выполнения программы NSwag с необходимыми параметрами для создания клиентского REST API. См. NSwag-команды и параметры.

    Вы можете захватить выходные данные из <Exec>, добавив ConsoleToMsBuild="true" в тег <Exec>, а затем используя параметр ConsoleOutput в теге <Output> для их захвата. ConsoleOutput возвращает выходные данные в виде Item. Пробелы обрезаются. ConsoleOutput включен, если ConsoleToMSBuild имеет значение true.

    Второй целевой объект, называемый forceReGenerationOnRebuild удаляет созданный класс во время очистки, чтобы принудительно выполнить повторное создание созданного кода во время выполнения целевого объекта перестроения. Этот целевой объект выполняется после предопределенного целевого объекта MSBuild CoreClean.

  8. Выполните перестроение решения Visual Studio и просмотрите клиент, созданный в папке PetShopRestClient.

  9. Теперь используйте созданный клиент. Перейдите к клиенту Program.csи скопируйте следующий код:

    using System;
    using System.Net.Http;
    
    namespace PetReaderExecTaskExample
    {
       internal class Program
       {
           private const string baseUrl = "https://petstore.swagger.io/v2";
           static void Main(string[] args)
           {
               HttpClient httpClient = new HttpClient();
               httpClient.BaseAddress = new Uri(baseUrl);
               var petClient = new PetShopRestClient.PetShopRestClient(httpClient);
               var pet = petClient.GetPetByIdAsync(1).Result;
               Console.WriteLine($"Id: {pet.Id} Name: {pet.Name} Status: {pet.Status} CategoryName: {pet.Category.Name}");
           }
       }
    }
    

    Заметка

    Этот код использует new HttpClient(), так как это просто для демонстрации, но это не рекомендуется для реального кода. Рекомендуется использовать HttpClientFactory для создания объекта HttpClient, который устраняет известные проблемы, связанные с запросом HttpClient, например нехваткой ресурсов или устаревшими проблемами DNS. См. использование IHttpClientFactory для реализации устойчивых HTTP-запросов.

Поздравляю! Теперь вы можете выполнить программу, чтобы узнать, как она работает.

Вариант 2. Пользовательская задача, производная от ToolTask

Во многих случаях использование задачи Exec достаточно хорошо, чтобы выполнить внешнее средство, чтобы сделать что-то подобное создание клиентского кода REST API, но что, если вы хотите разрешить создание клиентского кода REST API, если и только если вы не используете абсолютный путь Windows в качестве входных данных? Или что если вам нужно каким-то образом вычислить местоположение исполняемого файла? Если существует любая ситуация, когда необходимо выполнить некоторый код, чтобы выполнить дополнительную работу, задача средства MSBuild является лучшим решением. Класс ToolTask является абстрактным классом, производным от MSBuild Task. Вы можете определить конкретный подкласс, который создает настраиваемую задачу MSBuild. Этот подход позволяет запускать любой код, необходимый для подготовки к выполнению команд. Сначала следует ознакомиться с руководством создать настраиваемую задачу для создания кода.

Вы создадите пользовательскую задачу, основанную на MSBuild ToolTask, которая будет создавать клиент REST API, но она будет спроектирована так, чтобы выдавать ошибку, если вы попытаетесь использовать http-адрес для ссылки на спецификацию OpenAPI. NSwag поддерживает http-адрес как входные данные спецификации OpenAPI, но в целях этого примера предположим, что есть требование к проектированию, чтобы запретить это.

Полный код находится в этой папке PetReaderToolTaskExample; вы можете скачать и посмотреть. В этом руководстве вы шаг за шагом познакомитесь с некоторыми концепциями, которые можно применить в своих сценариях.

  1. Создайте проект Visual Studio для настраиваемой задачи. Назовите его RestApiClientGenerator и используйте шаблон библиотеки классов (C#) с .NET Standard 2.0. Назовите решение PetReaderToolTaskExample.

  2. Удалите Class1.cs, которое было создано автоматически.

  3. Добавьте пакеты Microsoft.Build.Utilities.Core NuGet:

    • Создание класса с именем RestApiClientGenerator

    • Наследуется от MSBuild ToolTask и реализует абстрактный метод, как показано в следующем коде:

      using Microsoft.Build.Utilities;
      
      namespace RestApiClientGenerator
      {
          public class RestApiClientGenerator : ToolTask
          {
              protected override string ToolName => throw new System.NotImplementedException();
      
              protected override string GenerateFullPathToTool()
              {
                  throw new System.NotImplementedException();
              }
          }
      }
      
  4. Добавьте следующие параметры:

    • InputOpenApiSpec, где указана спецификация
    • ClientClassName, имя созданного класса
    • ClientNamespaceName, пространство имен, в котором создается класс
    • FolderClientClass, путь к папке, в которой будет находиться класс.
    • NSwagCommandFullPath, полный путь к каталогу, где находится NSwag.exe
         [Required]
         public string InputOpenApiSpec { get; set; }
         [Required]
         public string ClientClassName { get; set; }
         [Required]
         public string ClientNamespaceName { get; set; }
         [Required]
         public string FolderClientClass { get; set; }
         [Required]
         public string NSwagCommandFullPath { get; set; }
    
  5. Установите средство командной строки NSwag. Вам потребуется полный путь к каталогу, где находится NSwag.exe.

  6. Реализуйте абстрактные методы:

       protected override string ToolName => "RestApiClientGenerator";
    
       protected override string GenerateFullPathToTool()
       {
           return $"{NSwagCommandFullPath}\\NSwag.exe";
       }
    
  7. Существует множество методов, которые можно переопределить. Для текущей реализации определите следующие два:

    • Определите параметр команды:
      protected override string GenerateCommandLineCommands()
      {
          return $"openapi2csclient /input:{InputOpenApiSpec}  /classname:{ClientClassName} /namespace:{ClientNamespaceName} /output:{FolderClientClass}\\{ClientClassName}.cs";
      }
    
    • Проверка параметров:
    protected override bool ValidateParameters()
    {
          //http address is not allowed
          var valid = true;
          if (InputOpenApiSpec.StartsWith("http:") || InputOpenApiSpec.StartsWith("https:"))
          {
              valid = false;
              Log.LogError("URL is not allowed");
          }
    
          return valid;
    }
    

    Заметка

    Эту простую проверку можно выполнить другим способом в MSBuild-файле, но рекомендуется сделать это в коде C# и инкапсулировать команду и логику.

  8. Создайте проект.

Создание консольного приложения для использования новой задачи MSBuild

Следующим шагом является создание приложения, использующего задачу.

  1. Создайте проект консольного приложения и назовите его PetReaderToolTaskConsoleApp. Выберите .NET 6.0. Пометьте его как запускаемый проект.

  2. Создайте проект библиотеки классов для создания кода с именем PetRestApiClient. Используйте .NET Standard 2.1.

  3. В проекте PetReaderToolTaskConsoleApp создайте зависимость проекта для PetRestApiClient.

  4. В проекте PetRestApiClient создайте папку PetRestApiClient. Эта папка будет содержать созданный код.

  5. Удалите Class1.cs, которое было создано автоматически.

  6. В PetRestApiClientдобавьте следующие пакеты NuGet:

    • Newtonsoft.Json, необходимый для компиляции созданного клиента
    • System.ComponentModel.Annotations, необходимый для компиляции созданного клиента
  7. В проекте PetRestApiClient создайте текстовый файл с именем petshop-openapi-spec.json (в папке проекта). Чтобы добавить спецификацию OpenAPI, скопируйте содержимое из здесь в файл. Мы любим воспроизводимую сборку, которая зависит только от входных данных, как описано ранее. В этом примере возникает ошибка сборки, если пользователь выбирает URL-адрес в качестве входных данных спецификации OpenAPI.

    Важный

    Общая перестройка не будет работать. Вы увидите ошибки, указывающие, что не удается скопировать или удалить RestApiClientGenerator.dll. Это потому, что пытается создать пользовательскую задачу MBuild в том же процессе сборки, который использует её. Выберите PetReaderToolTaskConsoleApp и перестроите только этот проект. Другим решением является размещение настраиваемой задачи в полностью независимом решении Visual Studio, как это было сделано в учебнике "Создание настраиваемой задачи" и примере.

  8. Скопируйте следующий код в Program.cs:

     using System;
     using System.Net.Http;
     namespace PetReaderToolTaskConsoleApp
     {
       internal class Program
       {
           private const string baseUrl = "https://petstore.swagger.io/v2";
           static void Main(string[] args)
           {
               HttpClient httpClient = new HttpClient();
               httpClient.BaseAddress = new Uri(baseUrl);
               var petClient = new PetRestApiClient.PetRestApiClient(httpClient);
               var pet = petClient.GetPetByIdAsync(1).Result;
               Console.WriteLine($"Id: {pet.Id} Name: {pet.Name} Status: {pet.Status} CategoryName: {pet.Category.Name}");
           }
       }
     }
    
  9. Измените инструкции MSBuild, чтобы вызвать задачу и создать код. Измените PetRestApiClient.csproj, выполнив следующие действия:

    1. Зарегистрируйте использование настраиваемой задачи MSBuild:

      <UsingTask TaskName="RestApiClientGenerator.RestApiClientGenerator" AssemblyFile="..\RestApiClientGenerator\bin\Debug\netstandard2.0\RestApiClientGenerator.dll" />
      
    2. Добавьте некоторые свойства, необходимые для выполнения задачи:

       <PropertyGroup>
          <!--The place where the OpenAPI spec is in-->
         <PetClientInputOpenApiSpec>petshop-openapi-spec.json</PetClientInputOpenApiSpec>
         <PetClientClientClassName>PetRestApiClient</PetClientClientClassName>
         <PetClientClientNamespaceName>PetRestApiClient</PetClientClientNamespaceName>
         <PetClientFolderClientClass>PetRestApiClient</PetClientFolderClientClass>
         <!--The directory where NSawg.exe is in-->
         <NSwagCommandFullPath>C:\Nsawg\Win</NSwagCommandFullPath>
        </PropertyGroup>
      

      Важный

      Выберите правильное NSwagCommandFullPath значение в зависимости от расположения установки в вашей системе.

    3. Добавьте целевой объект MSBuild для создания клиента во время процесса сборки. Этот целевой объект должен выполняться перед выполнением CoreCompile для создания кода, используемого в компиляции.

      <Target Name="generatePetClient" BeforeTargets="CoreCompile" Inputs="$(PetClientInputOpenApiSpec)" Outputs="$(PetClientFolderClientClass)\$(PetClientClientClassName).cs">
        <!--Calling our custom task derivated from MSBuild Tool Task-->
        <RestApiClientGenerator InputOpenApiSpec="$(PetClientInputOpenApiSpec)" ClientClassName="$(PetClientClientClassName)" ClientNamespaceName="$(PetClientClientNamespaceName)" FolderClientClass="$(PetClientFolderClientClass)" NSwagCommandFullPath="$(NSwagCommandFullPath)"></RestApiClientGenerator>
      </Target>
      
      <Target Name="forceReGenerationOnRebuild" AfterTargets="CoreClean">
        <Delete Files="$(PetClientFolderClientClass)\$(PetClientClientClassName).cs"></Delete>
      </Target>
      

    Input и Output связаны с инкрементальной сборкой, а цель forceReGenerationOnRebuild удаляет созданный файл после CoreClean, что приводит к повторной генерации клиента во время операции перестроения.

  10. Выберите PetReaderToolTaskConsoleApp и перестроите только этот проект. Теперь клиентский код создается и код компилируется. Его можно выполнить и узнать, как он работает. Этот код создает код из файла и допускается.

  11. На этом этапе вы продемонстрируете проверку параметров. В PetRestApiClient.csprojизмените свойство $(PetClientInputOpenApiSpec), чтобы использовать URL-адрес:

      <PetClientInputOpenApiSpec>https://petstore.swagger.io/v2/swagger.json</PetClientInputOpenApiSpec>
    
  12. Выберите PetReaderToolTaskConsoleApp и перестроите только этот проект. Вы получите сообщение об ошибке "URL-адрес не разрешен" в соответствии с требованием проектирования.

Скачивание кода

Установите средство командной строки NSwag . Затем вам потребуется полный путь к каталогу, где находится NSwag.exe. После этого измените PetRestApiClient.csproj и выберите соответствующее значение $(NSwagCommandFullPath) на основе пути установки на компьютере. Теперь выберите RestApiClientGenerator и создайте только этот проект, а затем выберите и перестроите PetReaderToolTaskConsoleApp. Можно выполнить PetReaderToolTaskConsoleApp. чтобы убедиться, что все работает должным образом.

Дальнейшие действия

Возможно, вы хотите опубликовать настраиваемую задачу в виде пакета NuGet.

Кроме того, узнайте, как протестировать настраиваемую задачу.