Bagikan melalui


Tutorial: Membuat permintaan HTTP di aplikasi konsol .NET menggunakan C#

Tutorial ini membangun aplikasi yang mengeluarkan permintaan HTTP ke layanan REST di GitHub. Aplikasi ini membaca informasi dalam format JSON dan mengonversi JSON menjadi objek C#. Mengonversi dari objek JSON ke C# dikenal sebagai deserialisasi.

Tutorial menunjukkan cara:

  • Kirim permintaan HTTP.
  • Mendeserialisasi respons JSON.
  • Mengonfigurasi deserialisasi dengan atribut.

Jika Anda lebih suka mengikuti sampel akhir untuk tutorial ini, Anda dapat mengunduhnya. Untuk petunjuk pengunduhan, lihat sampel dan Tutorial.

Prasyarat

Membuat aplikasi klien

  1. Buka perintah dan buat direktori baru untuk aplikasi Anda. Jadikan itu direktori saat ini.

  2. Masukkan perintah berikut di jendela konsol:

    dotnet new console --name WebAPIClient
    

    Perintah ini membuat file awal untuk aplikasi "Hello World" dasar. Nama proyek adalah "WebAPIClient".

  3. Navigasikan ke direktori "WebAPIClient", dan jalankan aplikasi.

    cd WebAPIClient
    
    dotnet run
    

    dotnet run secara otomatis dijalankan dotnet restore untuk memulihkan apa pun dependensi yang dibutuhkan aplikasi. Ini juga menjalankan dotnet build jika diperlukan. Anda sebaiknya melihat output aplikasi "Hello, World!". Di terminal Anda, tekan Ctrl+C untuk menghentikan aplikasi.

Membuat permintaan HTTP

Aplikasi ini memanggil GITHub API untuk mendapatkan informasi tentang proyek di bawah payung .NET Foundation . Titik akhir adalah https://api.github.com/orgs/dotnet/repos. Untuk mengambil informasi, ini membuat permintaan HTTP GET. Browser juga membuat permintaan HTTP GET, sehingga Anda dapat menempelkan URL tersebut ke bilah alamat browser Untuk melihat informasi apa yang akan Anda terima dan pemrosesan.

HttpClient Gunakan kelas untuk membuat permintaan HTTP. HttpClient hanya mendukung metode asinkron untuk API yang berjalan lama. Jadi langkah-langkah berikut membuat metode asinkron dan memanggilnya dari metode Utama.

  1. Program.cs Buka file di direktori proyek Anda dan ganti kontennya dengan yang berikut ini:

    await ProcessRepositoriesAsync();
    
    static async Task ProcessRepositoriesAsync(HttpClient client)
    {
    }
    

    kode ini:

    • Mengganti pernyataan Console.WriteLine dengan panggilan ke ProcessRepositoriesAsync yang menggunakan kata kunci await.
    • Mendefinisikan metode kosong ProcessRepositoriesAsync.
  2. Di kelas Program, gunakan HttpClient untuk mengatasi permintaan dan respons, dengan mengganti konten dengan kode C# berikut ini.

    using System.Net.Http.Headers;
    
    using HttpClient client = new();
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
    client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter");
    
    await ProcessRepositoriesAsync(client);
    
    static async Task ProcessRepositoriesAsync(HttpClient client)
    {
    }
    

    kode ini:

    • Menyiapkan header HTTP untuk semua permintaan:
      • Header Accept untuk menerima respons JSON
      • Sebuah User-Agent header. Header ini diperiksa oleh kode server GitHub dan diperlukan untuk mengambil informasi dari GitHub.
  3. Dalam metode ProcessRepositoriesAsync, panggil endpoint GitHub yang mengembalikan daftar semua repositori di bawah organisasi .NET Foundation:

     static async Task ProcessRepositoriesAsync(HttpClient client)
     {
         var json = await client.GetStringAsync(
             "https://api.github.com/orgs/dotnet/repos");
    
         Console.Write(json);
     }
    

    kode ini:

    • Menunggu tugas yang dikembalikan dari metode panggilan HttpClient.GetStringAsync(String) . Metode ini mengirimkan permintaan HTTP GET ke URI yang ditentukan. Isi respons dikembalikan sebagai String, yang tersedia saat tugas selesai.
    • String tanggapan json dicetak pada konsol.
  4. Buat aplikasi dan jalankan.

    dotnet run
    

    Tidak ada peringatan build karena sekarang terdapat operator ProcessRepositoriesAsync di dalam await. Keluaran merupakan tampilan panjang teks JSON.

Deserialisasi Hasil JSON

Langkah-langkah berikut menyederhanakan pendekatan untuk mengambil data dan memprosesnya. Anda akan menggunakan GetFromJsonAsync metode ekstensi yang menjadi bagian 📦 dari paket System.Net.Http.Json NuGet untuk mengambil dan mendeserialisasi hasil JSON ke dalam objek.

  1. Buat file bernama Repository.cs dan tambahkan kode berikut:

    public record class Repository(string Name);
    

    Kode sebelumnya mendefinisikan kelas untuk mewakili objek JSON yang dikembalikan dari API GitHub. Anda akan menggunakan kelas ini untuk menampilkan daftar nama repositori.

    Properti JSON untuk objek repositori berisi puluhan properti, tetapi hanya properti Name yang akan dideserialisasi. Serializer secara otomatis mengabaikan properti JSON yang tidak ada kecocokan di kelas target. Fitur ini memudahkan untuk membuat jenis yang hanya berfungsi dengan subset bidang dalam paket JSON besar.

    Meskipun metode yang GetFromJsonAsync akan Anda gunakan di titik berikutnya memiliki manfaat tidak peka huruf besar/kecil dalam hal nama properti, konvensi C# adalah untuk memanfaatkan huruf pertama nama properti.

  2. HttpClientJsonExtensions.GetFromJsonAsync Gunakan metode untuk mengambil dan mengonversi JSON menjadi objek C#. Ganti panggilan ke GetStringAsync(String) dalam ProcessRepositoriesAsync metode dengan baris berikut:

    var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos");
    

    Kode yang diperbarui menggantikan GetStringAsync(String) dengan HttpClientJsonExtensions.GetFromJsonAsync.

    Argumen pertama ke GetFromJsonAsync metode adalah await ekspresi. await ekspresi dapat muncul hampir di mana saja dalam kode Anda, meskipun hingga sekarang, Anda hanya melihatnya sebagai bagian dari pernyataan penugasan. Parameter berikutnya, requestUri bersifat opsional dan tidak harus disediakan jika sudah ditentukan saat membuat client objek. Anda tidak menyediakan client objek dengan URI untuk mengirim permintaan, jadi Anda menentukan URI sekarang. Parameter opsional terakhir, dihilangkan CancellationToken dalam cuplikan kode.

    Metode GetFromJsonAsync ini umum, yang berarti Anda menyediakan argumen jenis untuk jenis objek apa yang harus dibuat dari teks JSON yang diambil. Dalam contoh ini, Anda mendeserialisasi ke List<Repository>, yang merupakan objek generik lainnya, yaitu System.Collections.Generic.List<T>. Kelas List<T> menyimpan kumpulan objek. Argumen jenis mendeklarasikan jenis objek yang disimpan dalam List<T>. Argumen tipe adalah catatan Anda Repository, karena teks JSON mewakili kumpulan objek repositori.

  3. Tambahkan kode untuk menampilkan nama setiap repositori. Ganti baris yang berbunyi:

    Console.Write(json);
    

    dengan kode berikut:

    foreach (var repo in repositories ?? Enumerable.Empty<Repository>())
        Console.WriteLine(repo.Name);
    
  4. Direktif berikut using harus ada di bagian atas file:

    using System.Net.Http.Headers;
    using System.Net.Http.Json;
    
  5. Jalankan aplikasi.

    dotnet run
    

    Output adalah daftar nama repositori yang merupakan bagian dari .NET Foundation.

Refaktorisasi kode

Metode ini ProcessRepositoriesAsync dapat melakukan pekerjaan asinkron dan mengembalikan koleksi repositori. Ubah metode tersebut untuk mengembalikan Task<List<Repository>>, dan pindahkan kode yang menulis ke konsol di dekat pemanggilnya.

  1. Ubah tanda tangan ProcessRepositoriesAsync untuk mengembalikan tugas yang hasilnya adalah daftar Repository objek:

    static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)
    
  2. Kembalikan repositori setelah memproses respons JSON:

    var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos");
    return repositories ?? new();
    

    Pengkompilasi menghasilkan Task<T> objek untuk nilai pengembalian karena Anda telah menandai metode ini sebagai async.

  3. Ubah file Program.cs, mengganti panggilan ke ProcessRepositoriesAsync dengan yang berikut untuk mengambil hasil dan menulis setiap nama repositori ke konsol.

    var repositories = await ProcessRepositoriesAsync(client);
    
    foreach (var repo in repositories)
        Console.WriteLine(repo.Name);
    
  4. Jalankan aplikasi.

    Outputnya sama.

Deserialisasi lebih banyak properti

Dalam langkah-langkah berikut, kami memperluas kode untuk memproses lebih banyak properti dari payload JSON yang dikembalikan oleh API GitHub. Anda mungkin tidak perlu memproses setiap properti, tetapi menambahkan beberapa menunjukkan fitur C# tambahan.

  1. Ganti konten Repository kelas dengan definisi berikut record . Pastikan untuk mengimpor System.Text.Json.Serialization namespace dan menerapkan atribut [JsonPropertyName] untuk secara eksplisit memetakan bidang JSON ke properti C#.

     using System.Text.Json.Serialization;
    
     public record class Repository(
       string Name,
       string Description,
       [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl,
       Uri Homepage,
       int Watchers,
       [property: JsonPropertyName("pushed_at")] DateTime LastPushUtc
      );
    

    Jenis Uri dan int memiliki fungsionalitas bawaan untuk mengonversi ke dan dari representasi string. Tidak ada kode tambahan yang diperlukan untuk mendeserialisasi dari format string JSON ke jenis target tersebut. Jika paket JSON berisi data yang tidak dikonversi ke jenis target, tindakan serialisasi akan melemparkan pengecualian.

    JSON sering menggunakan lowercase atau snake_case untuk nama properti. Bidang seperti html_url dan pushed_at tidak mengikuti konvensi penamaan C# PascalCase. Menggunakan [JsonPropertyName] memastikan bahwa kunci JSON ini terikat dengan benar ke properti C# yang sesuai, bahkan ketika namanya berbeda jika atau berisi garis bawah. Pendekatan ini menjamin deserialisasi yang dapat diprediksi dan stabil sambil memungkinkan nama properti PascalCase dalam C#. Selain itu, metode GetFromJsonAsync ini digunakan case-insensitive ketika mencocokkan nama properti, jadi tidak ada konversi lebih lanjut yang diperlukan.

  2. Perbarui perulangan foreach dalam file Program.cs untuk menampilkan nilai properti:

    foreach (var repo in repositories)
    {
        Console.WriteLine($"Name: {repo.Name}");
        Console.WriteLine($"Homepage: {repo.Homepage}");
        Console.WriteLine($"GitHub: {repo.GitHubHomeUrl}");
        Console.WriteLine($"Description: {repo.Description}");
        Console.WriteLine($"Watchers: {repo.Watchers:#,0}");
        Console.WriteLine();
    }
    
  3. Jalankan aplikasi.

    Daftar ini sekarang menyertakan properti tambahan.

Menambahkan properti tanggal

Tanggal operasi pendorongan terakhir diformat dengan cara ini dalam respons JSON:

2016-02-08T21:27:00Z

Format ini untuk Waktu Universal Terkoordinasi (UTC), sehingga hasil deserialisasi adalah DateTime nilai yang propertinya Kind adalah Utc.

Untuk mendapatkan tanggal dan waktu yang diwakili di zona waktu, Anda harus menulis metode konversi kustom.

  1. Di Repository.cs, tambahkan properti untuk representasi UTC dari tanggal dan waktu dan properti readonly LastPush yang mengembalikan tanggal yang dikonversi ke waktu lokal, file akan terlihat seperti berikut ini:

    using System.Text.Json.Serialization;
    
    public record class Repository(
        string Name,
        string Description,
        [property: JsonPropertyName("html_url")] Uri GitHubHomeUrl,
        Uri Homepage,
        int Watchers,
        [property: JsonPropertyName("pushed_at")] DateTime LastPushUtc
        )
    {
        public DateTime LastPush => LastPushUtc.ToLocalTime();
    }
    

    Properti LastPush didefinisikan menggunakan anggota berwujud ekspresi untuk get aksesor. Tidak ada set aksesor. Menghilangkan set aksesor adalah salah satu cara untuk menentukan properti baca-saja di C#. (Ya, Anda dapat membuat properti tulis-saja di C#, tetapi nilainya terbatas.)

  2. Tambahkan pernyataan output lain di Program.cs: sekali lagi:

    Console.WriteLine($"Last push: {repo.LastPush}");
    
  3. Aplikasi lengkap harus menyerupai file Program.cs berikut:

    using System.Net.Http.Headers;
    using System.Net.Http.Json;
    
    using HttpClient client = new();
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(
        new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));
    client.DefaultRequestHeaders.Add("User-Agent", ".NET Foundation Repository Reporter");
    
    var repositories = await ProcessRepositoriesAsync(client);
    
    foreach (var repo in repositories)
    {
        Console.WriteLine($"Name: {repo.Name}");
        Console.WriteLine($"Homepage: {repo.Homepage}");
        Console.WriteLine($"GitHub: {repo.GitHubHomeUrl}");
        Console.WriteLine($"Description: {repo.Description}");
        Console.WriteLine($"Watchers: {repo.Watchers:#,0}");
        Console.WriteLine($"{repo.LastPush}");
        Console.WriteLine();
    }
    
    static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)
    {
        var repositories = await client.GetFromJsonAsync<List<Repository>>("https://api.github.com/orgs/dotnet/repos");
        return repositories ?? new List<Repository>();
    }
    
  4. Jalankan aplikasi.

    Output mencakup tanggal dan waktu pengunggahan terakhir ke setiap repositori.

Langkah berikutnya

Dalam tutorial ini, Anda membuat aplikasi yang membuat permintaan web dan mengurai hasilnya. Versi aplikasi Anda sekarang harus cocok dengan sampel yang sudah selesai.

Pelajari lebih lanjut tentang mengonfigurasi serialisasi JSON di Cara melakukan serialisasi dan deserialisasi (marshal dan unmarshal) JSON di .NET.