Chiamare un'API Web da un client .NET (C#)
Questo contenuto è per una versione precedente di .NET. Il nuovo sviluppo deve usare ASP.NET Core. Per altre informazioni sull'uso dell'API Web ASP.NET Core, vedere:
Scaricare il progetto completato.
Questa esercitazione illustra come chiamare un'API Web da un'applicazione .NET usando System.Net.Http.HttpClient.
In questa esercitazione viene scritta un'app client che usa l'API Web seguente:
Azione | Metodo HTTP | URI relativo |
---|---|---|
Ottenere un prodotto in base all'ID | GET | /api/products/id |
Creare un nuovo prodotto | POST | /api/products |
Aggiornare un prodotto | PUT | /api/products/id |
Eliminare un prodotto | DELETE | /api/products/id |
Per informazioni su come implementare questa API con API Web ASP.NET, vedere Creazione di un'API Web che supporta operazioni CRUD.
Per semplicità, l'applicazione client in questa esercitazione è un'applicazione console di Windows. HttpClient è supportato anche per le app Windows Phone e Windows Store. Per altre informazioni, vedere Scrittura di codice client API Web per più piattaforme tramite librerie portabili
NOTA: Se si passano URL di base e URL relativi come valori hardcoded, tenere presente le regole per l'uso dell'API HttpClient
. La HttpClient.BaseAddress
proprietà deve essere impostata su un indirizzo con una barra finale (/
). Ad esempio, quando si passano GLI URI delle risorse hardcoded al HttpClient.GetAsync
metodo, non includere una barra iniziale. Per ottenere un Product
ID:
- Impostare
client.BaseAddress = new Uri("https://localhost:5001/");
- Richiedere un
Product
oggetto . Ad esempio,client.GetAsync<Product>("api/products/4");
.
Creare l'applicazione console
In Visual Studio creare una nuova app console di Windows denominata HttpClientSample e incollare il codice seguente:
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();
}
}
}
Il codice precedente è l'app client completa.
RunAsync
esegue e blocca fino al completamento. La maggior parte dei metodi HttpClient è asincrona, perché esegue l'I/O di rete. Tutte le attività asincrone vengono eseguite all'interno RunAsync
di . In genere un'app non blocca il thread principale, ma questa app non consente alcuna interazione.
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();
}
Installare le librerie client api Web
Usare Gestione pacchetti NuGet per installare il pacchetto librerie client api Web.
Nel menu Strumenti selezionare Gestione pacchetti NuGet>Console di Gestione pacchetti. Nella console di Gestione pacchetti (PMC) digitare il comando seguente:
Install-Package Microsoft.AspNet.WebApi.Client
Il comando precedente aggiunge i pacchetti NuGet seguenti al progetto:
- Microsoft.AspNet.WebApi.Client
- Newtonsoft.Json
Newtonsoft.Json (noto anche come Json.NET) è un framework JSON ad alte prestazioni popolare per .NET.
Aggiungere una classe modello
Esaminare la 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; }
}
Questa classe corrisponde al modello di dati usato dall'API Web. Un'app può usare HttpClient per leggere un'istanza da una Product
risposta HTTP. L'app non deve scrivere alcun codice di deserializzazione.
Creare e inizializzare HttpClient
Esaminare la proprietà HttpClient statica:
static HttpClient client = new HttpClient();
HttpClient deve essere creata un'istanza una volta e riutilizzata in tutta la vita di un'applicazione. Le condizioni seguenti possono causare errori SocketException :
- Creazione di una nuova istanza httpClient per richiesta.
- Server con carico elevato.
La creazione di una nuova istanza httpClient per richiesta può esaurire i socket disponibili.
Il codice seguente inizializza l'istanza di 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"));
Il codice precedente:
- Imposta l'URI di base per le richieste HTTP. Modificare il numero di porta nella porta usata nell'app server. L'app non funzionerà a meno che non venga usata la porta per l'app server.
- Imposta l'intestazione Accept su "application/json". L'impostazione di questa intestazione indica al server di inviare dati in formato JSON.
Inviare una richiesta GET per recuperare una risorsa
Il codice seguente invia una richiesta GET per un prodotto:
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;
}
Il metodo GetAsync invia la richiesta HTTP GET. Al termine del metodo, restituisce un httpResponseMessage contenente la risposta HTTP. Se il codice di stato nella risposta è un codice riuscito, il corpo della risposta contiene la rappresentazione JSON di un prodotto. Chiamare ReadAsAsync per deserializzare il payload JSON in un'istanza Product
. Il metodo ReadAsAsync è asincrono perché il corpo della risposta può essere arbitrariamente grande.
HttpClient non genera un'eccezione quando la risposta HTTP contiene un codice di errore. La proprietà IsSuccessStatusCode è invece false se lo stato è un codice di errore. Se si preferisce considerare i codici di errore HTTP come eccezioni, chiamare HttpResponseMessage.EnsureSuccessStatusCode nell'oggetto response. EnsureSuccessStatusCode
genera un'eccezione se il codice di stato rientra nell'intervallo 200-299. Si noti che HttpClient può generare eccezioni per altri motivi, ad esempio se la richiesta viene esaurita.
Media-Type Formattatori da Deserializzare
Quando ReadAsAsync viene chiamato senza parametri, usa un set predefinito di formattatori multimediali per leggere il corpo della risposta. I formattatori predefiniti supportano dati con codifica JSON, XML e Form-URL.
Anziché usare i formattatori predefiniti, è possibile fornire un elenco di formattatori al metodo ReadAsAsync . L'uso di un elenco di formattatori è utile se si dispone di un formattatore di tipo multimediale personalizzato:
var formatters = new List<MediaTypeFormatter>() {
new MyCustomFormatter(),
new JsonMediaTypeFormatter(),
new XmlMediaTypeFormatter()
};
resp.Content.ReadAsAsync<IEnumerable<Product>>(formatters);
Per altre informazioni, vedere Formati multimediali in API Web ASP.NET 2
Invio di una richiesta POST per creare una risorsa
Il codice seguente invia una richiesta POST che contiene un'istanza Product
in 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;
}
Metodo PostAsJsonAsync :
- Serializza un oggetto in JSON.
- Invia il payload JSON in una richiesta POST.
Se la richiesta ha esito positivo:
- Deve restituire una risposta 201 (creata).
- La risposta deve includere l'URL delle risorse create nell'intestazione Location.
Invio di una richiesta PUT per aggiornare una risorsa
Il codice seguente invia una richiesta PUT per aggiornare un prodotto:
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;
}
Il metodo PutAsJsonAsync funziona come PostAsJsonAsync, ad eccezione del fatto che invia una richiesta PUT anziché POST.
Invio di una richiesta DELETE per eliminare una risorsa
Il codice seguente invia una richiesta DELETE per eliminare un prodotto:
static async Task<HttpStatusCode> DeleteProductAsync(string id)
{
HttpResponseMessage response = await client.DeleteAsync(
$"api/products/{id}");
return response.StatusCode;
}
Come GET, una richiesta DELETE non ha un corpo della richiesta. Non è necessario specificare il formato JSON o XML con DELETE.
Testare l'esempio
Per testare l'app client:
Scaricare ed eseguire l'app server. Verificare che l'app server funzioni. Ad esempio,
http://localhost:64195/api/products
deve restituire un elenco di prodotti.Impostare l'URI di base per le richieste HTTP. Modificare il numero di porta impostando la porta usata nell'app server.
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"));
Eseguire l'app client. Viene prodotto l'output seguente:
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)