Ao desenvolver aplicações que interagem com serviços externos, como APIs de tradução ou sistemas de alerta, a comunicação HTTP é uma necessidade frequente. Em C#, a classe HttpClient, parte do namespace System.Net.Http, oferece uma maneira robusta e flexível de realizar requisições HTTP, tanto para operações GET quanto POST. Este artigo explora como encapsular e utilizar HttpClient de forma eficiente.
Encapsulando Operações HTTP
Para simplificar o uso de HttpClient e garantir uma estrutura de código limpa, podemos criar uma classe utilitária estática. Esta classe pode gerenciar a instância de HttpClient e fornecer métodos convenientes para as operações mais comuns.
Configuração Inicial
A instância de HttpClient deve ser configurada adequadamente. É recomendado utilizar um HttpClientHandler para gerenciar aspectos como o uso de cookies. A inicialização deve ocorrer uma única vez para reutilização, evitando a sobrecarga de criar novas instâncias repetidamente.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
namespace MeuApp.Servicos
{
public static class HttpHelper
{
private static readonly Uri BaseUri = new Uri("https://api.example.com/");
private static readonly HttpClient client;
static HttpHelper()
{
var handler = new HttpClientHandler
{
UseCookies = true // Habilita o uso de cookies
};
client = new HttpClient(handler)
{
BaseAddress = BaseUri
};
// Configurações adicionais como timeouts podem ser definidas aqui
// client.Timeout = TimeSpan.FromSeconds(30);
}
public static async Task<string> GetAsync(string endpoint)
{
var response = await client.GetAsync(endpoint);
response.EnsureSuccessStatusCode(); // Lança exceção para códigos de erro HTTP
return await response.Content.ReadAsStringAsync();
}
public static async Task<string> PostAsync(string endpoint, Dictionary<string, string> formData)
{
var content = new FormUrlEncodedContent(formData);
var response = await client.PostAsync(endpoint, content);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
public static async Task<string> PostAsync(string endpoint, string jsonData)
{
var content = new StringContent(jsonData, System.Text.Encoding.UTF8, "application/json");
var response = await client.PostAsync(endpoint, content);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
}
Convenções de Nomenclatura e Estrutura
É uma boa prática organizar as chamadas de API em métodos específicos dentro de classes dedicadas, que podem, por sua vez, utilizar a classe utilitária HttpHelper. Por exemplo, uma operação de login pode ser encapsulada em um método dedicado.
using System.Collections.Generic;
using System.Threading.Tasks;
namespace MeuApp.Servicos
{
public class AuthService
{
public async Task<LoginResult> AuthenticateAsync(Dictionary<string, string> credentials)
{
const string loginEndpoint = "auth/login";
string rawResult = await HttpHelper.PostAsync(loginEndpoint, credentials);
// Deserializar rawResult para LoginResult (implementação omitida)
// Exemplo: var result = System.Text.Json.JsonSerializer.Deserialize<LoginResult>(rawResult);
var result = new LoginResult { Successed = true, Message = "Login bem-sucedido" }; // Placeholder
return result;
}
}
public class ResultBase
{
public string ErrorCode { get; set; }
public string Message { get; set; }
}
public class LoginResult : ResultBase
{
public bool Successed { get; set; }
// Construtor e lógica de desserialização seriam adicionados aqui
}
}
Tratametno de Respostas
Após receber uma resposta do servidor, é essencial processá-la. Isso pode envolver a desserialização de dados JSON, a verificação de códigos de status HTTP e a manipulação de mensagens de erro. A classe LoginResult, por exemplo, pode ser estendida para incluir a lógica de análise da resposta bruta.