Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
В этом руководстве создается приложение, которое выдает HTTP-запросы к службе REST на GitHub. Приложение считывает сведения в формате JSON и преобразует JSON в объекты C#. Преобразование из JSON в объекты C# называется десериализацией.
В руководстве показано, как:
- Отправка HTTP-запросов.
- Десериализация ответов JSON.
- Настройте десериализацию с помощью атрибутов.
Если вы предпочитаете следовать последнему образцу этого руководства, его можно скачать. Инструкции по скачиванию смотрите в разделах Образцы и руководства.
Предпосылки
- Последняя версия .NET SDK
- Visual Studio Code редактор
- C# DevKit
Создание клиентского приложения
Откройте командную строку и создайте новый каталог для приложения. Сделайте этот каталог текущим.
Введите следующую команду в окне консоли:
dotnet new console --name WebAPIClientЭта команда создает начальные файлы для базового приложения Hello World. Имя проекта — WebAPIClient.
Перейдите в каталог WebAPIClient и запустите приложение.
cd WebAPIClientdotnet rundotnet runавтоматически запускаетdotnet restoreдля восстановления всех зависимостей, которые требуются приложению. Он выполняется также при необходимостиdotnet build. Вы увидите выходные данные"Hello, World!"приложения. В терминале нажмите клавиши CTRL+C , чтобы остановить приложение.
Создание HTTP-запросов
Это приложение вызывает API GitHub , чтобы получить сведения о проектах под зонтиком .NET Foundation . Конечная точка https://api.github.com/orgs/dotnet/repos. Чтобы получить сведения, он делает HTTP-запрос GET. Браузеры также делают HTTP-запросы GET, поэтому вы можете вставить этот URL-адрес в адресную строку браузера, чтобы узнать, какие данные вы будете получать и обрабатывать.
HttpClient Используйте класс для выполнения HTTP-запросов. HttpClient поддерживает только асинхронные методы для своих долговременных API. Поэтому следующие шаги создают асинхронный метод и вызывают его из метода Main.
Откройте файл в каталоге
Program.csпроекта и замените его содержимое следующим образом:await ProcessRepositoriesAsync(); static async Task ProcessRepositoriesAsync(HttpClient client) { }Этот код:
- Заменяет инструкцию
Console.WriteLineвызовомProcessRepositoriesAsync, с использованием ключевого словаawait. - Определяет пустой
ProcessRepositoriesAsyncметод.
- Заменяет инструкцию
ProgramВ классе используйте HttpClient для обработки запросов и ответов, заменив содержимое следующим кодом C#.using System.Net.Http.Headers; using HttpClient client = new(); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json")); client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter"); await ProcessRepositoriesAsync(client); static async Task ProcessRepositoriesAsync(HttpClient client) { }Этот код:
- Настраивает заголовки HTTP для всех запросов:
- Заголовок
Acceptдля принятия ответов JSON - Заголовок
User-Agent. Эти заголовки проверяются кодом сервера GitHub и необходимы для получения сведений из GitHub.
- Заголовок
- Настраивает заголовки HTTP для всех запросов:
В методе
ProcessRepositoriesAsyncвызовите конечную точку GitHub, которая возвращает список всех репозиториев в организации .NET foundation:static async Task ProcessRepositoriesAsync(HttpClient client) { var json = await client.GetStringAsync( "https://api.github.com/orgs/dotnet/repos"); Console.Write(json); }Этот код:
- Ожидает задачу, возвращенную в результате вызова метода HttpClient.GetStringAsync(String). Этот метод отправляет HTTP-запрос GET в указанный универсальный код ресурса (URI). Текст ответа возвращается как объект String, который доступен при завершении задачи.
- Строка
jsonответа выводится в консоль.
Создайте приложение и запустите его.
dotnet runПредупреждение о сборке отсутствует, так как теперь
ProcessRepositoriesAsyncсодержит операторawait. Выходные данные — это длинное отображение текста JSON.
Десериализация результата JSON
Ниже описано, как упростить подход к выбору данных и обработке данных. Вы будете использовать GetFromJsonAsync метод расширения, который входит в 📦 пакет NuGet System.Net.Http.Json , чтобы получить и десериализировать результаты JSON в объекты.
Создайте файл с именем Repository.cs и добавьте следующий код:
public record class Repository(string Name);Предыдущий код определяет класс для представления объекта JSON, возвращаемого из API GitHub. Этот класс будет использоваться для отображения списка имен репозитория.
JSON для объекта репозитория содержит десятки свойств, но только
Nameсвойство будет десериализировано. Сериализатор автоматически игнорирует свойства JSON, для которых нет совпадений в целевом классе. Эта функция упрощает создание типов, которые работают только с подмножеством полей в большом пакете JSON.Несмотря на
GetFromJsonAsyncто, что метод, который будет использоваться в следующей точке, имеет преимущество без учета регистра, когда дело доходит до имен свойств, соглашение C# заключается в том, чтобы заглавить первую букву имен свойств.HttpClientJsonExtensions.GetFromJsonAsync Используйте метод для получения и преобразования JSON в объекты C#. Замените вызов GetStringAsync(String) в методе
ProcessRepositoriesAsyncследующими строками:var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos");Обновленный код заменяет GetStringAsync(String) на HttpClientJsonExtensions.GetFromJsonAsync.
Первым аргументом
GetFromJsonAsyncметодаawaitявляется выражение.awaitвыражения могут отображаться практически в любом месте кода, даже если до сих пор вы видели их только как часть инструкции назначения. Следующий параметрrequestUriявляется необязательным и не должен быть указан, если он уже указан при созданииclientобъекта. Вы не предоставили объекту универсальныйclientкод ресурса (URI) для отправки запроса, поэтому вы указали универсальный код ресурса (URI). Последний необязательный параметрCancellationTokenопущен в фрагменте кода.Метод
GetFromJsonAsyncявляется универсальным, что означает, что вы предоставляете аргументы типа для того, какой тип объектов следует создать из полученного текста JSON. В этом примере вы выполняете десериализацию в объектList<Repository>, который является другим универсальным объектом, System.Collections.Generic.List<T>. КлассList<T>хранит коллекцию объектов. Аргумент типа объявляет тип объектов, хранящихся в объектеList<T>. Аргумент типа — это запись форматаRepository, поскольку текст JSON представляет собой коллекцию объектов репозитория.Добавьте код для отображения имени каждого репозитория. Замените строки, гласящие:
Console.Write(json);указанным ниже кодом:
foreach (var repo in repositories ?? Enumerable.Empty<Repository>()) Console.WriteLine(repo.Name);В верхней части файла должны присутствовать следующие
usingдирективы:using System.Net.Http.Headers; using System.Net.Http.Json;Запустите приложение.
dotnet runВыходные данные — это список имен репозиториев, которые являются частью .NET Foundation.
Рефакторинг кода
Метод ProcessRepositoriesAsync может выполнять асинхронную работу и возвращать коллекцию репозиториев. Измените этот метод, чтобы он возвращал Task<List<Repository>>, и переместите код, который выводится в консоль, рядом с местом вызова.
Измените сигнатуру
ProcessRepositoriesAsyncдля возврата задачи, результатом которой является списокRepositoryобъектов:static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)Верните репозитории после обработки ответа JSON:
var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos"); return repositories ?? new();Компилятор создает
Task<T>объект для возвращаемого значения, так как этот метод помечен какasync.Измените файл Program.cs , заменив вызов
ProcessRepositoriesAsyncследующим образом, чтобы записать результаты и записать каждое имя репозитория в консоль.var repositories = await ProcessRepositoriesAsync(client); foreach (var repo in repositories) Console.WriteLine(repo.Name);Запустите приложение.
Выходные данные одинаковы.
Десериализация дополнительных свойств
В следующих шагах мы расширим код для обработки дополнительных свойств полезных данных JSON, возвращаемых API GitHub. Возможно, вам не потребуется обрабатывать каждое свойство, но добавление нескольких демонстрирует дополнительные возможности C#.
Замените содержимое
Repositoryкласса следующимrecordопределением. Обязательно импортируйтеSystem.Text.Json.Serializationпространство имен и примените[JsonPropertyName]атрибут для сопоставления полей JSON с свойствами C# явным образом.using System.Text.Json.Serialization; public record class Repository( string Name, string Description, [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl, Uri Homepage, int Watchers, [property: JsonPropertyName("pushed_at")] DateTime LastPushUtc );Типы Uri и
intимеют встроенные функции для преобразования в строковое представление и обратно. Дополнительный код не требуется для десериализации из формата строки JSON в эти целевые типы. Если пакет JSON содержит данные, которые не преобразуются в целевой тип, действие сериализации создает исключение.JSON часто использует
lowercaseилиsnake_caseв качестве имен свойств. Такие поля, какhtml_urlиpushed_atне следуют соглашениям об именовании C# PascalCase. Использование[JsonPropertyName]гарантирует правильность привязки этих ключей JSON к соответствующим свойствам C#, даже если их имена отличаются в случае или содержат подчеркивания. Этот подход гарантирует прогнозируемую и стабильную десериализацию, позволяя определение имен свойств в стиле PascalCase в C#. Кроме того,GetFromJsonAsyncметод используетсяcase-insensitiveпри сопоставлении имен свойств, поэтому дальнейшее преобразование не требуется.foreachОбновите цикл в файле Program.cs, чтобы отобразить значения свойств:foreach (var repo in repositories) { Console.WriteLine($"Name: {repo.Name}"); Console.WriteLine($"Homepage: {repo.Homepage}"); Console.WriteLine($"GitHub: {repo.GitHubHomeUrl}"); Console.WriteLine($"Description: {repo.Description}"); Console.WriteLine($"Watchers: {repo.Watchers:#,0}"); Console.WriteLine(); }Запустите приложение.
Теперь список содержит дополнительные свойства.
Добавьте свойство даты
Дата последней операции передачи форматируется следующим образом в ответе JSON:
2016-02-08T21:27:00Z
Этот формат предназначен для времени по универсальному координированному времени (UTC), поэтому результат десериализации — это значение DateTime, и его свойство Kind имеет значение Utc.
Чтобы получить дату и время, представленные в часовом поясе, необходимо написать пользовательский метод преобразования.
В Repository.cs добавьте свойство для представления даты и времени в формате UTC и свойство readonly
LastPush, которое возвращает дату, преобразованную в местное время, файл должен выглядеть следующим образом:using System.Text.Json.Serialization; public record class Repository( string Name, string Description, [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl, Uri Homepage, int Watchers, [property: JsonPropertyName("pushed_at")] DateTime LastPushUtc ) { public DateTime LastPush => LastPushUtc.ToLocalTime(); }Свойство
LastPushопределяется с помощью члена, основанного на выражении дляgetаксессора. Нетsetакцессора. Опущениеsetметода доступа является одним из способов определения свойства только для чтения в C#. (Да, можно создать свойства только для записи в C#, но их значение ограничено.)Добавьте еще одну инструкцию вывода в Program.cs: снова:
Console.WriteLine($"Last push: {repo.LastPush}");Полное приложение должно выглядеть следующим Program.cs файлом:
using System.Net.Http.Headers; using System.Net.Http.Json; using HttpClient client = new(); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json")); client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter"); var repositories = await ProcessRepositoriesAsync(client); foreach (var repo in repositories) { Console.WriteLine($"Name: {repo.Name}"); Console.WriteLine($"Homepage: {repo.Homepage}"); Console.WriteLine($"GitHub: {repo.GitHubHomeUrl}"); Console.WriteLine($"Description: {repo.Description}"); Console.WriteLine($"Watchers: {repo.Watchers:#,0}"); Console.WriteLine($"{repo.LastPush}"); Console.WriteLine(); } static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client) { var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos"); return repositories ?? new List<Repository>(); }Запустите приложение.
Выходные данные включают дату и время последнего отправки в каждый репозиторий.
Дальнейшие действия
В этом руководстве вы создали приложение, которое выполняет веб-запросы и анализирует результаты. Версия приложения должна соответствовать готовому образцу.
Подробнее о том, как настроить сериализацию JSON, читайте в разделе "Как сериализовать и десериализовать (маршалировать и демаршалировать) JSON в .NET.