Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом руководстве создается приложение, которое выдает 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 WebAPIClient
dotnet run
dotnet 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
Следующие шаги преобразуют ответ JSON в объекты C#. Вы используете класс System.Text.Json.JsonSerializer для десериализации JSON в объекты.
Создайте файл с именем Repository.cs и добавьте следующий код:
public record class Repository(string name);
Предыдущий код определяет класс для представления объекта JSON, возвращаемого из API GitHub. Этот класс будет использоваться для отображения списка имен репозитория.
JSON для объекта репозитория содержит десятки свойств, но только
name
свойство будет десериализировано. Сериализатор автоматически игнорирует свойства JSON, для которых нет совпадений в целевом классе. Эта функция упрощает создание типов, которые работают только с подмножеством полей в большом пакете JSON.Соглашение C# состоит в том, чтобы писать первую букву имен свойств с заглавной буквы, но
name
свойство здесь начинается со строчной буквы, так как это соответствует тому, что в JSON. Позже вы узнаете, как использовать имена свойств C#, которые не соответствуют именам свойств JSON.Используйте сериализатор для преобразования JSON в объекты C#. Замените вызов GetStringAsync(String) в методе
ProcessRepositoriesAsync
следующими строками:await using Stream stream = await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); var repositories = await JsonSerializer.DeserializeAsync<List<Repository>>(stream);
Обновленный код заменяет GetStringAsync(String) на GetStreamAsync(String). Этот метод сериализатора использует поток вместо строки в качестве источника.
Первым аргументом для JsonSerializer.DeserializeAsync<TValue>(Stream, JsonSerializerOptions, CancellationToken) является выражение
await
.await
выражения могут отображаться практически в любом месте кода, даже если до сих пор вы видели их только как часть инструкции назначения. Другие два параметра,JsonSerializerOptions
аCancellationToken
также необязательные и опущены в фрагменте кода.Этот
DeserializeAsync
метод является универсальным, что означает, что вы предоставляете аргументы типа для того, какой тип объектов следует создать из текста 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.Write(repo.name);
В верхней части файла должны присутствовать следующие
using
директивы:using System.Net.Http.Headers; using System.Text.Json;
Запустите приложение.
dotnet run
Выходные данные — это список имен репозиториев, которые являются частью .NET Foundation.
Настройка десериализации
В Repository.cs замените содержимое файла следующим кодом C#.
using System.Text.Json.Serialization; public record class Repository( [property: JsonPropertyName("name")] string Name);
Этот код:
- Переименовывает свойство
name
вName
. - Добавляет JsonPropertyNameAttribute для указания того, как это свойство отображается в формате JSON.
- Переименовывает свойство
В Program.cs обновите код, чтобы использовать новое написание с заглавной буквы для свойства
Name
.foreach (var repo in repositories) Console.Write(repo.Name);
Запустите приложение.
Выходные данные одинаковы.
Рефакторинг кода
Метод ProcessRepositoriesAsync
может выполнять асинхронную работу и возвращать коллекцию репозиториев. Измените этот метод, чтобы он возвращал Task<List<Repository>>
, и переместите код, который выводится в консоль, рядом с местом вызова.
Измените сигнатуру
ProcessRepositoriesAsync
для возврата задачи, результатом которой является списокRepository
объектов:static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)
Верните репозитории после обработки ответа JSON:
await using Stream stream = await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); var repositories = await JsonSerializer.DeserializeAsync<List<Repository>>(stream); return repositories ?? new();
Компилятор создает
Task<T>
объект для возвращаемого значения, так как этот метод помечен какasync
.Измените файл Program.cs , заменив вызов
ProcessRepositoriesAsync
следующим образом, чтобы записать результаты и записать каждое имя репозитория в консоль.var repositories = await ProcessRepositoriesAsync(client); foreach (var repo in repositories) Console.Write(repo.Name);
Запустите приложение.
Выходные данные одинаковы.
Десериализация дополнительных свойств
В следующих шагах добавьте код для обработки большего числа свойств в полученном пакете JSON. Возможно, вы не хотите обрабатывать каждое свойство, но добавление еще нескольких демонстрирует другие функции C#.
Замените содержимое
Repository
класса следующимrecord
определением:using System.Text.Json.Serialization; public record class Repository( [property: JsonPropertyName("name")] string Name, [property: JsonPropertyName("description")] string Description, [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl, [property: JsonPropertyName("homepage")] Uri Homepage, [property: JsonPropertyName("watchers")] int Watchers);
Типы Uri и
int
имеют встроенные функции для преобразования в строковое представление и обратно. Дополнительный код не требуется для десериализации из формата строки JSON в эти целевые типы. Если пакет JSON содержит данные, которые не преобразуются в целевой тип, действие сериализации создает исключение.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( [property: JsonPropertyName("name")] string Name, [property: JsonPropertyName("description")] string Description, [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl, [property: JsonPropertyName("homepage")] Uri Homepage, [property: JsonPropertyName("watchers")] 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.Text.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) { await using Stream stream = await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos"); var repositories = await JsonSerializer.DeserializeAsync<List<Repository>>(stream); return repositories ?? new(); }
Запустите приложение.
Выходные данные включают дату и время последнего отправки в каждый репозиторий.
Дальнейшие действия
В этом руководстве вы создали приложение, которое выполняет веб-запросы и анализирует результаты. Версия приложения должна соответствовать готовому образцу.
Подробнее о том, как настроить сериализацию JSON, читайте в разделе "Как сериализовать и десериализовать (маршалировать и демаршалировать) JSON в .NET.