Получение данных в формате JSON

Последнее обновление: 19.10.2022

JSON представляет один из наиболее популярных форматов передачи данных от клиента серверу и обратно. Посмотрим, как получать от сервера данные в формате JSON.

Определение сервера

Для начала определим сервер, который и будет посылать данные в формате JSON. Для этого Для этого создадим проект ASP.NET по типу ASP.NET Core Empty:

Определение сервера для приложения ASP.NET Core Web API для тестирования HttpClient в C# и .NET

К примеру, в моем случае проект называется HttpClientTestApp. Откроем в этом проекте в файл Program.cs

Создание сервиса ASP.NET для HttpClient в C#

и определим в нем следующий код:

var builder = WebApplication.CreateBuilder();
var app = builder.Build();

app.MapGet("/", () => new Person("Tom", 38));

app.Run();
record Person(string Name, int Age);

Для создания веб-приложения на ASP.NET Core вначале нам необходимо создать объект WebApplicationBuilder:

var builder = WebApplication.CreateBuilder();

Затем с помощью его метода Build создаем объект WebApplication, который собственно представляет приложение ASP.NET:

var app = builder.Build();

С помощью метода app.MapGet() определяем конечную точку - обработчик запросов по определенному маршруту:

app.MapGet("/", () => new Person("Tom", 38));

В данном случае при обращении по адресу "/" (то есть к корню веб-приложения) обработчик возвращает объект Person("Tom", 38), который при отправке автоматически сериализуется в формат JSON.

Затем запускаем приложение:

app.Run();

Запустим проект, и браузер нам отобразит отправленный объект в формате JSON:

Получение от приложения ASP.NET данных в JSON с помощью HttpClient в C# и .NET

Сразу обратим внимание на адрес, по которому запущено приложение ASP.NET, чтобы затем подключиться к нему из HttpClient. Так, в моем случае это "https://localhost:7094/".

Определение клиента

Непосредственно класс HttpClient не определяет удобной функциональности для автоматического получения данных в JSON. Однако в пространстве имен System.Net.Http.Json определены методы расширения для HttpClient специально для работы с Json:

  • GetFromJsonAsync(): отправляет запрос GET и возвращает десериализованные объекты из JSON

  • DeleteFromJsonAsync(): отправляет запрос DELETE и возвращает десериализованные объекты из JSON

Оба метода практически идентичны, кроме типа отправляемого запроса. Нетипизированная версия получает как минимум два параметра - адрес запроса и тип, в который надо десериализовать данные:

using System.Net.Http.Json; // пространство имен метода GetFromJsonAsync

class Program
{
    static HttpClient httpClient = new HttpClient();
    static async Task Main()
    {
        object? data = await httpClient.GetFromJsonAsync("https://localhost:7094/", typeof(Person));
        if(data is Person person)
        {
            Console.WriteLine($"Name: {person.Name}   Age: {person.Age}");
        }
    }
}
record Person(string Name, int Age);

Нетипизированная версия возвращает данные в виде объекта object?, который надо затем приводить к нужному типу.

Так, в данном случае мы пытаемся десериализовать данные в объект Person, который соответствует отправляемым на сервере данным. В итоге мы получим следующий консольный вывод

Name: Tom   Age: 38

При типизированной версии метод тизируется классом, в который надо десериализовать данные. А в качестве параметров достаточно передать адрес запроса:

using System.Net.Http.Json;

class Program
{
    static HttpClient httpClient = new HttpClient();
    static async Task Main()
    {
        Person? person = await httpClient.GetFromJsonAsync<Person>("https://localhost:7094/");
        Console.WriteLine($"Name: {person?.Name}   Age: {person?.Age}");
    }
}
record Person(string Name, int Age);

В качестве результата возвращается объект типа, которым типизируется метод и который допускает значение null.

В обоих случае если десериализация данных в объект указанного типа завершится неудачно, в этом случае результат метода будет равен null

Метод ReadFromJsonAsync класса HttpContent

Хотя примеры выше в принципе нормально работают, но в некоторых ситуациях мы можем столкнуться с ограничениями. Так, что есть мы хотим считать статус ответа, какие-то заголовки? Например, изменим код сервера следующим образом:

var builder = WebApplication.CreateBuilder();
var app = builder.Build();

app.MapGet("/{id?}", (int? id) =>
{
    if (id is null)
        return Results.BadRequest(new { Message = "Некорректные данные в запросе" });
    else if (id != 1)
        return Results.NotFound(new { Message = $"Объект с id={id} не существует" });
    else
        return Results.Json(new Person("Bob", 42));
});

app.Run();
record Person(string Name, int Age);

Теперь метод app.MapGet прикреплен к запросам, которые соответствуют шаблону "/{id?}". В данном случае пользователь после слеша может указать некоторое значение, и это значение будет передано в параметр id. Вопросительный знак ? после названия параметра id указывает, что этот параметр необязательный. То есть шаблон "/{id?}" будет соответствовать запросам "/" (в этом случае id равен null) или "/5" (в этом случае id равен 5). Причем если после слеша указано значение, оно должно представлять число.

В обработчике этого маршрута проверяем значение параметра id. Так, если оно равно null, то посылаем клиенту ошибку 400 с одним сообщением:

return Results.BadRequest(new { Message = "Некорректные данные в запросе" });

Если id указан, но он не равен 1, посылаем ошибку 404 с другим сообщением:

return Results.NotFound(new { Message = $"Объект с id={id} не существует" });

В остальных случаях посылаем объект Person:

return Results.Json(new Person("Bob", 42));

Для отправки данных здесь применяются методы класса Results, но все они сериализуют переданные в них объекты в Json. Это довольно обычная ситуация, потому что нередко ответ сервера вовлекает статусные коды, сообщения об ошибках и прочую информацию, которая может потребоваться на клиенте.

Как в этом случае мы можем обработать все эти возможные варианты? В этом случае мы можем вместо получения непосредственно отправленных данных получать ответ сервера в виде HttpMessageResponse, который даст нам доступ ко всей сопутствующей информации как заголовки, статус и т.д. Тогда мы можем получить из HttpMessageResponse ответ в виде объекта HttpContent, у которого затем вызывается метод ReadFromJsonAsyn(). Этот метод определен в пространстве имен System.Net.Http.Json. Он типизируется типом, в который надо десериализовать данные:

using System.Net;
using System.Net.Http.Json;
class Program
{
    static HttpClient httpClient = new HttpClient();
    static async Task Main()
    {
        using var response = await httpClient.GetAsync("https://localhost:7094/1"); 

        if (response.StatusCode == HttpStatusCode.BadRequest || response.StatusCode == HttpStatusCode.NotFound)
        {
            // получаем информацию об ошибке
            Error? error = await response.Content.ReadFromJsonAsync<Error>();
            Console.WriteLine(response.StatusCode);
            Console.WriteLine(error?.Message);
        }
        else
        {
            // если запрос завершился успешно, получаем объект Person
            Person? person = await response.Content.ReadFromJsonAsync<Person>();
            Console.WriteLine($"Name: {person?.Name}   Age: {person?.Age}");
        }
    }
}
// для успешного ответа
record Person(string Name, int Age);
// для ошибок
record Error(string Message);

В зависимости от статуса ответа считываем ответ с помощью метода ReadFromJsonAsync() объекта HttpContent в один из типов - Person или Error.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850