NET 5 - Explorando o namespace System.Net.Http.Json

 Hoje vamos explorar o novo namespace System.Net.Http.Json presente no .NET 5.

Dentre os muitos recursos que o .NET 5 trouxe, temos agora um novo namespace System.Net.Http.Json que fornece métodos de extensão para as classes HttpClient e HttpContent que realiza a serialização e desserialização usando o System.Text.Json.

Existem 3 classes principais neste namespace:

  1. HttpClientJsonExtensions que fornece métodos de extensão para enviar/receber conteúdo HTTP como JSON;
  2. HttpContentJsonExtensions que fornece métodos de extensão para ler e analisar o HttpContent do JSON;
  3. JsonContent, que fornece conteúdo HTTP baseado em JSON;

Vamos dar uma espiada em cada uma delas e ver como funcionam.

1- HttpClientJsonExtensions

Essa classe inclui três métodos (cada um com várias sobrecargas veja a documentação):

  1. GetFromJsonAsync que envia um request GET para a Uri especificada e retorna o valor resultante da desserialização do body do response como um JSON de forma assíncrona;
     
  2. PostAsJsonAsync que envia um request POST para a Uri especificada contendo um valor serializado como JSON no body dp request de forma assíncrona;

Abaixo temos um trecho de código que mostra como usar estes métodos e como isso era feito antes do .NET 5:

Os códigos mostrados a seguir usam uma classe Cliente :

public class Cliente
{
    public string Nome { get; set; }
    public string Email { get; set; }
    public int Idade { get; set; }
}

1- Usando System.Net.Http.Json com .NET 5.0

static async Task Main(string[] args)
{
     var httpClient = new HttpClient();
     httpClient.BaseAddress = new Uri("https://localhost:5000");
     // Usando System.Net.Http.Json com .NET 5.0
     var clientes = await httpClient.GetFromJsonAsync<Cliente[]>("api/usuarios/clientes");
     var perfil = new Cliente { Nome = "Anthony", Email = "macoratti@yahoo.com", Idade = 39 };
     using var response1 = await httpClient.PostAsJsonAsync("api/usuarios/clientes", perfil);
     response1.EnsureSuccessStatusCode();
      var updatedCliente = new Cliente { Nome = "Tony", Email = "macoratti@yahoo.com", Idade = 40 };
      using var response2 = await httpClient.PutAsJsonAsync("api/usuarios/clientes", perfil);
      response2.EnsureSuccessStatusCode();
 }

2-  Usando System.Net.Http Antes do NET 5.0

static async Task Main(string[] args)
{
     var httpClient = new HttpClient();
     httpClient.BaseAddress = new Uri("https://localhost:5000");
     // Usando System.Net.Http antes do .NET 5.0
     var clientes = await httpClient.GetFromJsonAsync<Cliente[]>("api/usuarios/clientes");
   // Para usar ReadAsAsync, precisa do pacote Microsoft.AspNet.WebApi.Client
     using var response3 = await httpClient.GetAsync("api/usuarios/clientes");

     if (response3.IsSuccessStatusCode)
          clientes = await response3.Content.ReadAsAsync<Cliente[]>();
     var perfil = new Cliente { Nome = "Jose Carlos", Email = "macoratti@yahoo.com", Idade = 39 };
     var json = JsonSerializer.Serialize(perfil);
     var stringContent = new StringContent(json, Encoding.UTF8, "application/json");
     using var response4 = await httpClient.PostAsync("api/usuarios/clientes", stringContent);

     response4.EnsureSuccessStatusCode();
     var updatedCliente = new Cliente { Nome = "Jose Carlos", Email = "macoratti@yahoo.com", Idade = 40 };
     json = JsonSerializer.Serialize(perfil);
     stringContent = new StringContent(json, Encoding.UTF8, "application/json");
     using var response5 = await httpClient.PutAsync("api/usuarios/clientes", stringContent);
     response5.EnsureSuccessStatusCode();
 }

Comparando a utilização dos métodos vemos que a utilização da classe HttpClient é feita de forma mais suscinta e leve.

2- HttpContentJsonExtensions

Essa classes contêm apenas o método ReadFromJsonAsync que tem duas sobrecargas.

Esses métodos de extensão lêem o conteúdo HTTP e retornam o valor resultante da desserialização do conteúdo como JSON de forma assíncrona.

Vejamos um exemplo de código no NET 5.0 e antes do NET 5.0.

1- Usando System.Net.Http.Json no .NET 5.0

using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
namespace NET5_HttpJson
{
    internal class Program
    {
        private static async Task Main(string[] args)
        {
            var httpClient = new HttpClient();
            httpClient.BaseAddress = new Uri("https://localhost:5000");
            // Usando System.Net.Http.Json no NET 5.0
            var request = new HttpRequestMessage(HttpMethod.Get, "api/usuarios/clientes");
            using var response1 = await httpClient.SendAsync(request);
            if (response1.IsSuccessStatusCode)
            {
                var clientes = await response1.Content.ReadFromJsonAsync<Cliente[]>();
            }
        }
    }
}

2- Obtendo a partir HttpContent JSON antes do .NET 5

using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
namespace NET5_HttpJson
{
    internal class Program
    {
        private static async Task Main(string[] args)
        {
            var httpClient = new HttpClient();
            httpClient.BaseAddress = new Uri("https://localhost:5000");
             // Obtendo a partir HttpContent JSON antes do .NET 5
            var request = new HttpRequestMessage(HttpMethod.Get, "api/users/profiles");
            using var response2 = await httpClient.SendAsync(request);
            if (response2.IsSuccessStatusCode)
            {
                using var streamResult = await response2.Content.ReadAsStreamAsync();
                var profiles = JsonSerializer.DeserializeAsync<Cliente[]>(streamResult);
            }
        }
    }
} 

Aqui também usar o código no ambiente do .NET 5.0 é um pouco mais simples!

Você precisará usar esse método de extensão se não preferir usar a classe HttpClientJsonExtensions.

O método ReadFromJsonAsync é feito para fazer a mesma coisa que GetFromJsonAsync, mas se aplica a HttpContent que é retornado por SendAsync.

2- JsonContent

Essa classe fornece conteúdo HTTP baseado em JSON. É importante notar que JsonContent herda de HttpContent, então ele compartilha todos os métodos e propriedades do HttpContent.

Então, o que há de novo no JsonContent ?

Esta classe agora cria um método que não é um método de extensão. Este método permite criar um HttpContent baseado em JSON para instanciar um HttpRequestMessage a ser passado para o método SendAsync. Isso pode ser usado como uma alternativa aos métodos de extensão PostAsJsonAsync ou PutAsJsonAsync ou para compensar o método de extensão PatchAsJsonAsync ausente.

Exemplo de uso:

  using System;
  using System.Net.Http;
  using System.Net.Http.Json;
  using System.Threading.Tasks;
     class Program
    {
        private static async Task Main(string[] args)
        {
            var httpClient = new HttpClient();
            var uri = "https://localhost:5000";
            httpClient.BaseAddress = new Uri(uri);
            // Usando System.Net.Http.Json com .NET 5
            // Usando JsonContent e SendAsync ao invés de PostAsJsonAsync
            var requestMessage = new HttpRequestMessage(HttpMethod.Post, "https://localhost:5000")
            {
                Content = JsonContent.Create(new Cliente { Nome = "Jose", Email = "macoratti@yahoo.com", Idade = 40 })
            };
            using var reponse1 = await httpClient.SendAsync(requestMessage);
            reponse1.EnsureSuccessStatusCode();
            // Com .NET 5  Postando dados a partir de JSON com PostAsJsonAsync
            var perfil = new Cliente { Nome = "Jose", Email = "macoratti@yahoo.com", Idade = 39 };
            using var response2 = await httpClient.PostAsJsonAsync("api/usuarios/clientes", perfil);
            response2.EnsureSuccessStatusCode();
        }
    }

Assim o namespace   System.Net.Http.Json traz alguns recursos interessantes, todos baseados em System.Text.Json, que é um assembly de melhor desempenho para serializar/desserializar JSON.

E estamos conversados..

"Porque do céu se manifesta a ira de Deus sobre toda a impiedade e injustiça dos homens, que detêm a verdade em injustiça."
Romanos 1:18


Referências:


José Carlos Macoratti