Volání webového rozhraní API z klienta .NET (C#)

Tento obsah je určený pro předchozí verzi rozhraní .NET. Nový vývoj by měl používat ASP.NET Core. Další informace o používání webového rozhraní API ASP.NET Core najdete tady:

Stáhněte si dokončený projekt.

V tomto kurzu se dozvíte, jak volat webové rozhraní API z aplikace .NET pomocí System.Net.Http.HttpClient.

V tomto kurzu je napsána klientská aplikace, která využívá následující webové rozhraní API:

Akce Metoda HTTP Relativní identifikátor URI
Získání produktu podle ID GET /api/products/id
Vytvoření nového produktu POST /api/products
Aktualizace produktu PUT /api/products/id
Odstranění produktu DELETE /api/products/id

Informace o implementaci tohoto rozhraní API s webovým rozhraním API ASP.NET najdete v tématu Vytvoření webového rozhraní API, které podporuje operace CRUD.

Pro zjednodušení je klientskou aplikací v tomto kurzu konzolová aplikace systému Windows. HttpClient je také podporován pro Windows Phone a aplikace pro Windows Store. Další informace najdete v tématu Psaní kódu klienta webového rozhraní API pro více platforem pomocí přenosných knihoven.

POZNÁMKA: Pokud předáváte základní adresy URL a relativní identifikátory URI jako pevně zakódované hodnoty, mějte na paměti pravidla pro využití HttpClient rozhraní API. Vlastnost HttpClient.BaseAddress by měla být nastavená na adresu s koncovým lomítkem (/). Například při předávání pevně zakódovaných identifikátorů URI prostředků metodě HttpClient.GetAsync nezahrnujte počáteční lomítko. Získání Product id podle:

  1. Nastavit client.BaseAddress = new Uri("https://localhost:5001/");
  2. Vyžádejte si .Product Například, client.GetAsync<Product>("api/products/4");.

Vytvoření konzolové aplikace

V sadě Visual Studio vytvořte novou konzolovou aplikaci pro Windows s názvem HttpClientSample a vložte následující kód:

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();
        }
    }
}

Předchozí kód je kompletní klientská aplikace.

RunAsync se spustí a zablokuje, dokud se to neskonče. Většina metod HttpClient je asynchronní, protože provádějí síťové vstupně-výstupní operace. Všechny asynchronní úlohy se provádějí uvnitř RunAsync. Aplikace obvykle neblokuje hlavní vlákno, ale tato aplikace neumožňuje žádnou interakci.

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();
}

Instalace klientských knihoven webového rozhraní API

Pomocí Správce balíčků NuGet nainstalujte balíček klientských knihoven webového rozhraní API.

V nabídce Nástroje vyberteKonzola Správce>balíčků NuGet. V konzole Správce balíčků (PMC) zadejte následující příkaz:

Install-Package Microsoft.AspNet.WebApi.Client

Předchozí příkaz přidá do projektu následující balíčky NuGet:

  • Microsoft.AspNet.WebApi.Client
  • Newtonsoft.Json

Newtonsoft.Json (označovaný také jako Json.NET) je oblíbená vysoce výkonná architektura JSON pro .NET.

Přidání třídy modelu

Product Prozkoumejte třídu:

public class Product
{
    public string Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Category { get; set; }
}

Tato třída odpovídá datovému modelu používanému webovým rozhraním API. Aplikace může použít HttpClient ke čtení Product instance z odpovědi HTTP. Aplikace nemusí psát žádný deserializační kód.

Vytvoření a inicializace HttpClient

Prozkoumejte statickou vlastnost HttpClient :

static HttpClient client = new HttpClient();

Cílem httpClient je vytvořit instanci jednou a opakovaně používat po celou dobu životnosti aplikace. Následující podmínky můžou vést k chybám SocketException :

  • Vytvoření nové instance HttpClient pro každý požadavek
  • Server s velkým zatížením.

Vytvoření nové instance HttpClient na požadavek může vyčerpat dostupné sokety.

Následující kód inicializuje instanci 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"));

Předchozí kód:

  • Nastaví základní identifikátor URI pro požadavky HTTP. Změňte číslo portu na port použitý v serverové aplikaci. Aplikace nebude fungovat, pokud se nepoužije port pro serverové aplikace.
  • Nastaví hlavičku Accept na application/json. Nastavení této hlavičky informuje server, aby odesílal data ve formátu JSON.

Odeslání požadavku GET pro načtení prostředku

Následující kód odešle požadavek GET pro produkt:

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;
}

Metoda GetAsync odešle požadavek HTTP GET. Po dokončení metody vrátí HttpResponseMessage , která obsahuje odpověď HTTP. Pokud je stavovým kódem v odpovědi kód úspěchu, tělo odpovědi obsahuje reprezentaci produktu ve formátu JSON. Volání readAsAsync k deserializaci datové části JSON na Product instanci. Metoda ReadAsAsync je asynchronní, protože tělo odpovědi může být libovolně velké.

HttpClient nevyvolá výjimku, pokud odpověď HTTP obsahuje kód chyby. Místo toho isSuccessStatusCode vlastnost je false , pokud je stav kód chyby. Pokud chcete kódy chyb HTTP považovat za výjimky, zavolejte httpResponseMessage.EnsureSuccessStatusCode objekt odpovědi . EnsureSuccessStatusCode vyvolá výjimku, pokud stavový kód spadá mimo rozsah 200–299. Všimněte si, že HttpClient může vyvolat výjimky z jiných důvodů – například pokud vyprší časový limit požadavku.

Media-Type formátovací moduly k deserializaci

Při zavolání ReadAsAsync bez parametrů se používá výchozí sada formátovačů médií ke čtení textu odpovědi. Výchozí formátovací moduly podporují data zakódovaná ve formátu JSON, XML a form-url.

Místo použití výchozích formátovačů můžete poskytnout seznam formátovačů metodě ReadAsAsync . Použití seznamu formátovačů je užitečné, pokud máte vlastní formátovací typ média:

var formatters = new List<MediaTypeFormatter>() {
    new MyCustomFormatter(),
    new JsonMediaTypeFormatter(),
    new XmlMediaTypeFormatter()
};
resp.Content.ReadAsAsync<IEnumerable<Product>>(formatters);

Další informace najdete v tématu Formátování médií ve webovém rozhraní API ASP.NET 2.

Odeslání požadavku POST na vytvoření prostředku

Následující kód odešle požadavek POST, který obsahuje Product instanci ve formátu 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;
}

Metoda PostAsJsonAsync :

  • Serializuje objekt do formátu JSON.
  • Odešle datovou část JSON v požadavku POST.

Pokud je požadavek úspěšný:

  • Měla by vrátit odpověď 201 (Vytvořeno).
  • Odpověď by měla obsahovat adresu URL vytvořených prostředků v záhlaví Umístění.

Odeslání požadavku PUT na aktualizaci prostředku

Následující kód odešle požadavek PUT na aktualizaci produktu:

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;
}

Metoda PutAsJsonAsync funguje podobně jako PostAsJsonAsync s tím rozdílem, že odesílá požadavek PUT místo POST.

Odeslání požadavku DELETE na odstranění prostředku

Následující kód odešle požadavek DELETE na odstranění produktu:

static async Task<HttpStatusCode> DeleteProductAsync(string id)
{
    HttpResponseMessage response = await client.DeleteAsync(
        $"api/products/{id}");
    return response.StatusCode;
}

Podobně jako GET nemá požadavek DELETE text požadavku. Pomocí příkazu DELETE nemusíte zadávat formát JSON nebo XML.

Otestování ukázky

Testování klientské aplikace:

  1. Stáhněte a spusťte serverové aplikace. Ověřte, že serverová aplikace funguje. Měl by například http://localhost:64195/api/products vrátit seznam produktů.

  2. Nastavte základní identifikátor URI pro požadavky HTTP. Změňte číslo portu na port použitý v serverové aplikaci.

    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"));
    
  3. Spusťte klientskou aplikaci. Vytvoří se následující výstup:

    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)