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
Baixar Projeto Concluído. Baixar instruções.
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 Como criar uma API Web compatível com operações CRUD.
Para simplificar, o aplicativo cliente neste tutorial é um aplicativo de console do Windows. HttpClient também tem suporte para aplicativos Windows Phone e da Windows Store. Para obter mais informações, consulte Escrever 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 codificados em código, fique 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 codificados em código para o HttpClient.GetAsync
método, não inclua uma barra de avanço à esquerda. Para obter uma Product
ID por:
- Defina
client.BaseAddress = new Uri("https://localhost:5001/");
- Solicitar 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 no 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 é assíncrona, pois eles executam E/S de rede. Todas as tarefas assíncronas são feitas dentro RunAsync
. Normalmente, um aplicativo não bloqueia o thread principal, 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 do 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();
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 informa ao servidor para 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 de status na resposta for um código de sucesso, 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
gera uma exceção se o código de status estiver 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 formatores a desserializar
Quando ReadAsAsync é chamado sem parâmetros, ele usa um conjunto padrão de formatores 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 Formatores 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. Baixe as instruções. 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)