Chamar uma API Web de um cliente .NET (C#)
Esse conteúdo é para uma versão anterior do .NET. O novo desenvolvimento deve usar ASP.NET Core. Para obter mais informações sobre como usar ASP.NET Core API Web, consulte:
- Tutorial: criar uma API Web com o ASP.NET Core
- Chamar um ponto de extremidade HTTP de um cliente .NET
Este tutorial mostra como chamar uma API Web de um aplicativo .NET usando System.Net.Http.HttpClient.
Neste tutorial, um aplicativo cliente é escrito que consome a seguinte API Web:
Ação | Método HTTP | URI relativo |
---|---|---|
Obter um produto por ID | GET | /api/products/id |
Criar um novo produto | POST | /api/products |
Atualizar um produto | PUT | /api/products/id |
Excluir um produto | Delete (excluir) | /api/products/id |
Para saber como implementar essa API com ASP.NET Web API, consulte Criando uma API Web que dá suporte a operações CRUD.
Para simplificar, o aplicativo cliente neste tutorial é um aplicativo de console do Windows. Também há suporte para HttpClient para aplicativos Windows Phone e da Windows Store. Para obter mais informações, consulte Escrevendo código de cliente da API Web para várias plataformas usando bibliotecas portáteis
NOTA: Se você passar URLs base e URIs relativas como valores embutidos em código, esteja atento às regras para utilizar a HttpClient
API. A HttpClient.BaseAddress
propriedade deve ser definida como um endereço com uma barra à direita (/
). Por exemplo, ao passar URIs de recurso embutidos em código para o HttpClient.GetAsync
método , não inclua uma barra de avanço à esquerda. Para obter um Product
por ID:
- Defina
client.BaseAddress = new Uri("https://localhost:5001/");
- Solicite um
Product
. Por exemplo,client.GetAsync<Product>("api/products/4");
.
Criar o aplicativo de console
No Visual Studio, crie um novo aplicativo de console do Windows chamado HttpClientSample e cole o seguinte código:
using System;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace HttpClientSample
{
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
class Program
{
static HttpClient client = new HttpClient();
static void ShowProduct(Product product)
{
Console.WriteLine($"Name: {product.Name}\tPrice: " +
$"{product.Price}\tCategory: {product.Category}");
}
static async Task<Uri> CreateProductAsync(Product product)
{
HttpResponseMessage response = await client.PostAsJsonAsync(
"api/products", product);
response.EnsureSuccessStatusCode();
// return URI of the created resource.
return response.Headers.Location;
}
static async Task<Product> GetProductAsync(string path)
{
Product product = null;
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
product = await response.Content.ReadAsAsync<Product>();
}
return product;
}
static async Task<Product> UpdateProductAsync(Product product)
{
HttpResponseMessage response = await client.PutAsJsonAsync(
$"api/products/{product.Id}", product);
response.EnsureSuccessStatusCode();
// Deserialize the updated product from the response body.
product = await response.Content.ReadAsAsync<Product>();
return product;
}
static async Task<HttpStatusCode> DeleteProductAsync(string id)
{
HttpResponseMessage response = await client.DeleteAsync(
$"api/products/{id}");
return response.StatusCode;
}
static void Main()
{
RunAsync().GetAwaiter().GetResult();
}
static async Task RunAsync()
{
// Update port # in the following line.
client.BaseAddress = new Uri("http://localhost:64195/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
try
{
// Create a new product
Product product = new Product
{
Name = "Gizmo",
Price = 100,
Category = "Widgets"
};
var url = await CreateProductAsync(product);
Console.WriteLine($"Created at {url}");
// Get the product
product = await GetProductAsync(url.PathAndQuery);
ShowProduct(product);
// Update the product
Console.WriteLine("Updating price...");
product.Price = 80;
await UpdateProductAsync(product);
// Get the updated product
product = await GetProductAsync(url.PathAndQuery);
ShowProduct(product);
// Delete the product
var statusCode = await DeleteProductAsync(product.Id);
Console.WriteLine($"Deleted (HTTP Status = {(int)statusCode})");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
}
}
O código anterior é o aplicativo cliente completo.
RunAsync
executa e bloqueia até que ele seja concluído. A maioria dos métodos HttpClient são assíncronos, pois executam E/S de rede. Todas as tarefas assíncronas são feitas dentro RunAsync
de . Normalmente, um aplicativo não bloqueia o thread main, mas esse aplicativo não permite nenhuma interação.
static async Task RunAsync()
{
// Update port # in the following line.
client.BaseAddress = new Uri("http://localhost:64195/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
try
{
// Create a new product
Product product = new Product
{
Name = "Gizmo",
Price = 100,
Category = "Widgets"
};
var url = await CreateProductAsync(product);
Console.WriteLine($"Created at {url}");
// Get the product
product = await GetProductAsync(url.PathAndQuery);
ShowProduct(product);
// Update the product
Console.WriteLine("Updating price...");
product.Price = 80;
await UpdateProductAsync(product);
// Get the updated product
product = await GetProductAsync(url.PathAndQuery);
ShowProduct(product);
// Delete the product
var statusCode = await DeleteProductAsync(product.Id);
Console.WriteLine($"Deleted (HTTP Status = {(int)statusCode})");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.ReadLine();
}
Instalar as bibliotecas de clientes da API Web
Use o Gerenciador de Pacotes NuGet para instalar o pacote Bibliotecas de Clientes da API Web.
No menu Ferramentas selecione Gerenciador de Pacotes NuGet>Console do Gerenciador de Pacotes. No PMC (Console do Gerenciador de Pacotes), digite o seguinte comando:
Install-Package Microsoft.AspNet.WebApi.Client
O comando anterior adiciona os seguintes pacotes NuGet ao projeto:
- Microsoft.AspNet.WebApi.Client
- Newtonsoft.Json
Newtonsoft.Json (também conhecido como Json.NET) é uma estrutura JSON popular de alto desempenho para .NET.
Adicionar uma classe de modelo
Examine a classe Product
:
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
Essa classe corresponde ao modelo de dados usado pela API Web. Um aplicativo pode usar HttpClient para ler uma Product
instância de uma resposta HTTP. O aplicativo não precisa escrever nenhum código de desserialização.
Criar e inicializar HttpClient
Examine a propriedade HttpClient estática:
static HttpClient client = new HttpClient();
O HttpClient destina-se a ser instanciado uma vez e reutilizado ao longo da vida útil de um aplicativo. As seguintes condições podem resultar em erros SocketException :
- Criando uma nova instância httpClient por solicitação.
- Servidor sob carga pesada.
A criação de uma nova instância httpClient por solicitação pode esgotar os soquetes disponíveis.
O código a seguir inicializa a instância httpClient :
static async Task RunAsync()
{
// Update port # in the following line.
client.BaseAddress = new Uri("http://localhost:64195/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
O código anterior:
- Define o URI base para solicitações HTTP. Altere o número da porta para a porta usada no aplicativo do servidor. O aplicativo não funcionará a menos que a porta do aplicativo de servidor seja usada.
- Define o cabeçalho Accept como "application/json". Definir esse cabeçalho instrui o servidor a enviar dados no formato JSON.
Enviar uma solicitação GET para recuperar um recurso
O código a seguir envia uma solicitação GET para um produto:
static async Task<Product> GetProductAsync(string path)
{
Product product = null;
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
product = await response.Content.ReadAsAsync<Product>();
}
return product;
}
O método GetAsync envia a solicitação HTTP GET. Quando o método for concluído, ele retornará um HttpResponseMessage que contém a resposta HTTP. Se o código status na resposta for um código de êxito, o corpo da resposta conterá a representação JSON de um produto. Chame ReadAsAsync para desserializar o conteúdo JSON para uma Product
instância. O método ReadAsAsync é assíncrono porque o corpo da resposta pode ser arbitrariamente grande.
HttpClient não gera uma exceção quando a resposta HTTP contém um código de erro. Em vez disso, a propriedade IsSuccessStatusCode será falsa se o status for um código de erro. Se preferir tratar códigos de erro HTTP como exceções, chame HttpResponseMessage.EnsureSuccessStatusCode no objeto de resposta. EnsureSuccessStatusCode
gerará uma exceção se o código status ficar fora do intervalo de 200 a 299. Observe que o HttpClient pode gerar exceções por outros motivos , por exemplo, se a solicitação atingir o tempo limite.
Media-Type formatadores para desserializar
Quando ReadAsAsync é chamado sem parâmetros, ele usa um conjunto padrão de formatadores de mídia para ler o corpo da resposta. Os formatadores padrão dão suporte a dados codificados em JSON, XML e Form-url.
Em vez de usar os formatadores padrão, você pode fornecer uma lista de formatadores para o método ReadAsAsync . Usar uma lista de formatadores será útil se você tiver um formatador de tipo de mídia personalizado:
var formatters = new List<MediaTypeFormatter>() {
new MyCustomFormatter(),
new JsonMediaTypeFormatter(),
new XmlMediaTypeFormatter()
};
resp.Content.ReadAsAsync<IEnumerable<Product>>(formatters);
Para obter mais informações, consulte Formatadores de mídia no ASP.NET Web API 2
Enviando uma solicitação POST para criar um recurso
O código a seguir envia uma solicitação POST que contém uma Product
instância no formato JSON:
static async Task<Uri> CreateProductAsync(Product product)
{
HttpResponseMessage response = await client.PostAsJsonAsync(
"api/products", product);
response.EnsureSuccessStatusCode();
// return URI of the created resource.
return response.Headers.Location;
}
O método PostAsJsonAsync :
- Serializa um objeto para JSON.
- Envia o conteúdo JSON em uma solicitação POST.
Se a solicitação for bem-sucedida:
- Ele deve retornar uma resposta 201 (Criado).
- A resposta deve incluir a URL dos recursos criados no cabeçalho Local.
Enviando uma solicitação PUT para atualizar um recurso
O código a seguir envia uma solicitação PUT para atualizar um produto:
static async Task<Product> UpdateProductAsync(Product product)
{
HttpResponseMessage response = await client.PutAsJsonAsync(
$"api/products/{product.Id}", product);
response.EnsureSuccessStatusCode();
// Deserialize the updated product from the response body.
product = await response.Content.ReadAsAsync<Product>();
return product;
}
O método PutAsJsonAsync funciona como PostAsJsonAsync, exceto que ele envia uma solicitação PUT em vez de POST.
Enviando uma solicitação DELETE para excluir um recurso
O código a seguir envia uma solicitação DELETE para excluir um produto:
static async Task<HttpStatusCode> DeleteProductAsync(string id)
{
HttpResponseMessage response = await client.DeleteAsync(
$"api/products/{id}");
return response.StatusCode;
}
Assim como GET, uma solicitação DELETE não tem um corpo de solicitação. Você não precisa especificar o formato JSON ou XML com DELETE.
O exemplo de teste
Para testar o aplicativo cliente:
Baixe e execute o aplicativo de servidor. Verifique se o aplicativo de servidor está funcionando. Por exemplo,
http://localhost:64195/api/products
deve retornar uma lista de produtos.Defina o URI base para solicitações HTTP. Altere o número da porta para a porta usada no aplicativo do servidor.
static async Task RunAsync() { // Update port # in the following line. client.BaseAddress = new Uri("http://localhost:64195/"); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add( new MediaTypeWithQualityHeaderValue("application/json"));
Execute o aplicativo cliente. A seguinte saída é produzida:
Created at http://localhost:64195/api/products/4 Name: Gizmo Price: 100.0 Category: Widgets Updating price... Name: Gizmo Price: 80.0 Category: Widgets Deleted (HTTP Status = 204)