Freigeben über


Aufrufen einer Web-API von einem .NET-Client (C#)

Dieser Inhalt gilt für eine frühere Version von .NET. Neue Entwicklung sollte ASP.NET Core verwenden. Weitere Informationen zur Verwendung ASP.NET Core Web-API finden Sie unter:

Abgeschlossenes Projekt herunterladen.

In diesem Lernprogramm wird gezeigt, wie Sie eine Web-API aus einer .NET-Anwendung mithilfe von System.Net.Http.HttpClient aufrufen.

In diesem Lernprogramm wird eine Client-App geschrieben, die die folgende Web-API verwendet:

Action HTTP-Methode Relativer URI
Abrufen eines Produkts nach ID ERHALTEN/Bekommen /api/products/id
Neues Produkt erstellen POST /api/products
Aktualisieren eines Produkts PUT /api/products/id
Produkt löschen Löschen /api/products/id

Informationen zum Implementieren dieser API mit ASP.NET Web-API finden Sie unter Erstellen einer Web-API, die CRUD-Vorgänge unterstützt.

Der Einfachheit halber ist die Clientanwendung in diesem Lernprogramm eine Windows-Konsolenanwendung. HttpClient wird auch für Windows Phone- und Windows Store-Apps unterstützt. Weitere Informationen finden Sie unter Schreiben von Web-API-Clientcode für mehrere Plattformen mit portablen Bibliotheken

HINWEIS: Wenn Sie Basis-URLs und relative URIs als hartcodierte Werte übergeben, beachten Sie die Regeln für die Verwendung der HttpClient API. Die HttpClient.BaseAddress Eigenschaft (property) sollte auf eine Adresse mit einem abschließenden Schrägstrich (/) festgelegt werden. Wenn Sie beispielsweise hartcodierte Ressourcen-URIs an die HttpClient.GetAsync Methode übergeben, fügen Sie keinen führenden Schrägstrich ein. So rufen Sie eine Product nach ID ab:

  1. Legen Sie client.BaseAddress = new Uri("https://localhost:5001/"); fest.
  2. Fordern Sie ein Product an. Beispiel: client.GetAsync<Product>("api/products/4");.

Erstellen der Konsolenanwendung

Erstellen Sie in Visual Studio eine neue Windows-Konsolen-App mit dem Namen "HttpClientSample ", und fügen Sie den folgenden Code ein:

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

Der vorangehende Code ist die vollständige Client-App.

RunAsync wird ausgeführt und blockiert, bis es abgeschlossen ist. Die meisten HttpClient-Methoden sind asynchron, da sie Netzwerk-E/A ausführen. Alle asynchronen Aufgaben werden in RunAsyncdiesem Bereich ausgeführt. Normalerweise blockiert eine App den Hauptthread nicht, aber diese App lässt keine Interaktion zu.

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

Installieren der Web-API-Clientbibliotheken

Verwenden Sie den NuGet-Paket-Manager, um das Web-API-Clientbibliotheken-Paket zu installieren.

Wählen Sie im Menü Tools die Option NuGet-Paket-Manager>Paket-Manager-Konsole aus. Geben Sie in der Paket-Manager-Konsole (PMC) den folgenden Befehl ein:

Install-Package Microsoft.AspNet.WebApi.Client

Mit dem vorherigen Befehl werden dem Projekt die folgenden NuGet-Pakete hinzugefügt:

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

Newtonsoft.Json (auch bekannt als Json.NET) ist ein beliebtes HOCHLEISTUNGS-JSON-Framework für .NET.

Hinzufügen einer Modellklasse

Untersuchen Sie die Product Klasse:

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

Diese Klasse entspricht dem Datenmodell, das von der Web-API verwendet wird. Eine App kann httpClient verwenden, um eine Product Instanz aus einer HTTP-Antwort zu lesen. Die App muss keinen Deserialisierungscode schreiben.

Erstellen und Initialisieren von HttpClient

Überprüfen Sie die statische HttpClient-Eigenschaft :

static HttpClient client = new HttpClient();

HttpClient soll einmal instanziiert und während der gesamten Lebensdauer einer Anwendung wiederverwendet werden. Die folgenden Bedingungen können zu SocketException-Fehlern führen:

  • Erstellen einer neuen HttpClient-Instanz pro Anforderung.
  • Server unter hoher Last.

Das Erstellen einer neuen HttpClient-Instanz pro Anforderung kann die verfügbaren Sockets ausschöpfen.

Der folgende Code initialisiert die HttpClient-Instanz :

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"));

Der vorherige Code:

  • Legt den Basis-URI für HTTP-Anforderungen fest. Ändern Sie die Portnummer in den Port, der in der Server-App verwendet wird. Die App funktioniert nur, wenn der Port für die Server-App verwendet wird.
  • Legt den Accept-Header auf "application/json" fest. Durch Festlegen dieses Headers wird der Server aufgefordert, Daten im JSON-Format zu senden.

Senden einer GET-Anforderung zum Abrufen einer Ressource

Der folgende Code sendet eine GET-Anforderung für ein 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;
}

Die GetAsync-Methode sendet die HTTP-GET-Anforderung. Nach Abschluss der Methode wird eine HttpResponseMessage zurückgegeben, die die HTTP-Antwort enthält. Wenn der Statuscode in der Antwort ein Erfolgscode ist, enthält der Antworttext die JSON-Darstellung eines Produkts. Rufen Sie ReadAsAsync auf, um die JSON-Nutzlast in eine Product-Instanz zu deserialisieren. Die ReadAsAsync-Methode ist asynchron, da der Antworttext beliebig groß sein kann.

HttpClient löst keine Ausnahme aus, wenn die HTTP-Antwort einen Fehlercode enthält. Stattdessen ist die IsSuccessStatusCode-Eigenschaft"false ", wenn der Status ein Fehlercode ist. Wenn Sie HTTP-Fehlercodes lieber als Ausnahmen behandeln möchten, rufen Sie HttpResponseMessage.EnsureSuccessStatusCode für das Antwortobjekt auf. EnsureSuccessStatusCode löst eine Ausnahme aus, wenn der Statuscode außerhalb des Bereichs 200–299 liegt. Beachten Sie, dass HttpClient aus anderen Gründen Ausnahmen werfen kann, z. B. wenn eine Zeitüberschreitung bei der Anforderung auftritt.

Media-Typ-Formatter zum Deserialisieren

Wenn ReadAsAsync ohne Parameter aufgerufen wird, wird ein Standardsatz von Medienformatierern verwendet, um den Antworttext zu lesen. Die Standardformatierer unterstützen JSON-, XML- und Formular-URL-codierte Daten.

Statt die Standardformatierer zu verwenden, können Sie eine Liste von Formatierern für die ReadAsAsync-Methode bereitstellen. Die Verwendung einer Liste von Formatierern ist nützlich, wenn Sie über einen benutzerdefinierten Medientypformatierer verfügen:

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

Weitere Informationen finden Sie unter "Medienformatierer" in ASP.NET Web-API 2

Senden einer POST-Anforderung zum Erstellen einer Ressource

Der folgende Code sendet eine POST-Anforderung, die eine Product Instanz im JSON-Format enthält:

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

Die PostAsJsonAsync-Methode :

  • Serialisiert ein Objekt in JSON.
  • Sendet die JSON-Nutzlast in einer POST-Anforderung.

Wenn die Anforderung erfolgreich ist:

  • Es sollte eine 201 (Erstellt)-Antwort zurückgegeben werden.
  • Die Antwort sollte die URL der erstellten Ressourcen im Location-Header enthalten.

Senden einer PUT-Anforderung zum Aktualisieren einer Ressource

Der folgende Code sendet eine PUT-Anforderung zum Aktualisieren eines Produkts:

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

Die PutAsJsonAsync-Methode funktioniert wie PostAsJsonAsync, mit der Ausnahme, dass sie eine PUT-Anforderung anstelle von POST sendet.

Senden einer DELETE-Anforderung zum Löschen einer Ressource

Der folgende Code sendet eine DELETE-Anforderung zum Löschen eines Produkts:

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

Wie GET verfügt eine DELETE-Anforderung nicht über einen Anforderungstext. Sie müssen kein JSON- oder XML-Format mit DELETE angeben.

Beispiel testen

So testen Sie die Client-App:

  1. Laden Sie die Server-App herunter, und führen Sie sie aus. Überprüfen Sie, ob die Server-App funktioniert. http://localhost:64195/api/products Beispielsweise sollte eine Liste von Produkten zurückgegeben werden.

  2. Legen Sie den Basis-URI für HTTP-Anforderungen fest. Ändern Sie die Portnummer in den Port, der in der Server-App verwendet wird.

    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. Führen Sie die Client-App aus. Es wird die folgende Ausgabe generiert:

    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)