Öğretici: C kullanarak bir .NET konsol uygulamasında HTTP istekleri yapma #

Bu öğreticide GitHub'da bir REST hizmetine HTTP istekleri veren bir uygulama derlenir. Uygulama bilgileri JSON biçiminde okur ve JSON'ı C# nesnelerine dönüştürür. JSON'dan C# nesnelerine dönüştürme , seri durumdan çıkarma olarak bilinir.

Öğreticide şunların nasıl yapılacağını gösterilmektedir:

  • HTTP istekleri gönderin.
  • JSON yanıtlarını seri durumdan çıkarma.
  • Seri durumdan çıkarma özelliğini özniteliklerle yapılandırın.

Bu öğreticinin son örneğini takip etmek isterseniz indirebilirsiniz. İndirme yönergeleri için bkz . Örnekler ve Öğreticiler.

Önkoşullar

  • .NET SDK 6.0 veya üzeri
  • [Visual Studio Code (açık kaynak, platformlar arası düzenleyici) gibi bir kod düzenleyicisi. Örnek uygulamayı Windows, Linux veya macOS üzerinde ya da docker kapsayıcısında çalıştırabilirsiniz.

İstemci uygulamasını oluşturma

  1. Bir komut istemi açın ve uygulamanız için yeni bir dizin oluşturun. Bunu geçerli dizin yapın.

  2. Konsol penceresine aşağıdaki komutu girin:

    dotnet new console --name WebAPIClient
    

    Bu komut, temel bir "Merhaba Dünya" uygulaması için başlangıç dosyalarını oluşturur. Proje adı "WebAPIClient" şeklindedir.

  3. "WebAPIClient" dizinine gidin ve uygulamayı çalıştırın.

    cd WebAPIClient
    
    dotnet run
    

    dotnet run uygulamanın ihtiyaç duyduğu tüm bağımlılıkları geri yüklemek için otomatik olarak çalışır dotnet restore . Gerekirse de çalışır dotnet build . Uygulama çıkışını "Hello, World!"görmeniz gerekir. Uygulamayı durdurmak için terminalinizde Ctrl+C tuşlarına basın.

HTTP isteğinde bulunma

Bu uygulama, .NET Foundation şemsiyesi altındaki projeler hakkında bilgi almak için GitHub API'sini çağırır. Uç nokta şeklindedir https://api.github.com/orgs/dotnet/repos. Bilgileri almak için bir HTTP GET isteğinde bulunur. Tarayıcılar http GET istekleri de yapar, böylece hangi bilgileri alıp işleyebileceğinizi görmek için bu URL'yi tarayıcı adres çubuğuna yapıştırabilirsiniz.

HTTP istekleri yapmak için sınıfını HttpClient kullanın. HttpClient uzun süre çalışan API'leri için yalnızca zaman uyumsuz yöntemleri destekler. Bu nedenle aşağıdaki adımlar zaman uyumsuz bir yöntem oluşturur ve bunu Main yönteminden çağırır.

  1. Program.cs Dosyayı proje dizininizde açın ve içeriğini aşağıdakilerle değiştirin:

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

    Bu kod:

    • deyimini Console.WriteLine , anahtar sözcüğünü kullanan bir çağrısıyla ProcessRepositoriesAsyncawait değiştirir.
    • Boş ProcessRepositoriesAsync bir yöntem tanımlar.
  2. Program sınıfında, içeriği aşağıdaki C# ile değiştirerek istekleri ve yanıtları işlemek için kullanınHttpClient.

    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)
    {
    }
    

    Bu kod:

    • Tüm istekler için HTTP üst bilgilerini ayarlar:
      • Accept JSON yanıtlarını kabul etmek için üst bilgi
      • Üst User-Agent bilgi. Bu üst bilgiler GitHub sunucu kodu tarafından denetlenmektedir ve GitHub'dan bilgi almak için gereklidir.
  3. yönteminde ProcessRepositoriesAsync , .NET foundation kuruluşu altındaki tüm depoların listesini döndüren GitHub uç noktasını çağırın:

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

    Bu kod:

    • Çağırma HttpClient.GetStringAsync(String) yönteminden döndürülen görevi bekler. Bu yöntem, belirtilen URI'ye bir HTTP GET isteği gönderir. Yanıtın gövdesi, görev tamamlandığında kullanılabilen olarak Stringdöndürülür.
    • Yanıt dizesi json konsola yazdırılır.
  4. Uygulamayı derleyin ve çalıştırın.

    dotnet run
    

    artık bir await işleç içerdiğinden ProcessRepositoriesAsync derleme uyarısı yok. Çıktı, JSON metninin uzun bir görüntüsüdür.

JSON Sonucunu Seri Durumdan Çıkarma

Aşağıdaki adımlar JSON yanıtını C# nesnelerine dönüştürür. JSON'ı System.Text.Json.JsonSerializer nesneler halinde seri durumdan çıkarabilmek için sınıfını kullanırsınız.

  1. Repository.cs adlı bir dosya oluşturun ve aşağıdaki kodu ekleyin:

    public record class Repository(string name);
    

    Yukarıdaki kod, GitHub API'sinden döndürülen JSON nesnesini temsil eden bir sınıf tanımlar. Depo adlarının listesini görüntülemek için bu sınıfı kullanacaksınız.

    Bir depo nesnesi için JSON onlarca özellik içerir, ancak yalnızca özelliği seri durumdan name çıkarılır. Seri hale getirici, hedef sınıfta eşleşme olmayan JSON özelliklerini otomatik olarak yoksayar. Bu özellik, büyük bir JSON paketindeki alanların yalnızca bir alt kümesiyle çalışan türler oluşturmayı kolaylaştırır.

    C# kuralı, özellik adlarının ilk harfini büyük harfe çevirir, ancak name buradaki özellik JSON'dakiyle tam olarak eşleştiğinden küçük harfle başlar. Daha sonra, JSON özellik adlarına uymayan C# özellik adlarının nasıl kullanılacağını göreceksiniz.

  2. JSON'ı C# nesnelerine dönüştürmek için seri hale getiriciyi kullanın. yöntemindeki çağrısının GetStringAsync(String)ProcessRepositoriesAsync yerine aşağıdaki satırları ekleyin:

    await using Stream stream =
        await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos");
    var repositories =
        await JsonSerializer.DeserializeAsync<List<Repository>>(stream);
    

    Güncelleştirilen kod ile GetStreamAsync(String)değiştirilirGetStringAsync(String). Bu seri hale getirici yöntemi, kaynağı olarak dize yerine bir akış kullanır.

    için ilk bağımsız değişken JsonSerializer.DeserializeAsync<TValue>(Stream, JsonSerializerOptions, CancellationToken) bir await ifadedir. await ifadeleri kodunuzda neredeyse her yerde görünebilir, ancak şimdiye kadar bunları yalnızca atama deyiminin bir parçası olarak gördünüz. ve diğer iki parametre JsonSerializerOptionsCancellationTokenisteğe bağlıdır ve kod parçacığında atlanır.

    DeserializeAsync yöntemi geneldir, yani JSON metninden oluşturulması gereken nesne türleri için tür bağımsız değişkenleri sağlarsınız. Bu örnekte, başka bir genel nesne System.Collections.Generic.List<T>olan bir List<Repository>için seri durumdan çıkarıyorsunuz. List<T> sınıfı bir nesne koleksiyonu depolar. tür bağımsız değişkeni, içinde List<T>depolanan nesnelerin türünü bildirir. JSON metni bir depo nesneleri koleksiyonunu temsil ettiğinden tür bağımsız değişkeni kaydınızdır Repository .

  3. Her deponun adını görüntülemek için kod ekleyin. Şu satırları değiştirin:

    Console.Write(json);
    

    aşağıdaki kodla:

    foreach (var repo in repositories ?? Enumerable.Empty<Repository>())
        Console.Write(repo.name);
    
  4. Dosyanın en üstünde aşağıdaki using yönergeler bulunmalıdır:

    using System.Net.Http.Headers;
    using System.Text.Json;
    
  5. Uygulamayı çalıştırın.

    dotnet run
    

    Çıktı, .NET Foundation'ın parçası olan depoların adlarının listesidir.

Seri durumdan çıkarma yapılandırma

  1. Repository.cs dosyasında dosya içeriğini aşağıdaki C# ile değiştirin.

    using System.Text.Json.Serialization;
    
    public record class Repository(
        [property: JsonPropertyName("name")] string Name);
    

    Bu kod:

    • Özelliğin name adını olarak Namedeğiştirir.
    • bu özelliğin JsonPropertyNameAttribute JSON'da nasıl görüneceğini belirtmek için öğesini ekler.
  2. Program.cs dosyasında, özelliğin yeni büyük harf kullanımını kullanmak için kodu güncelleştirinName:

    foreach (var repo in repositories)
       Console.Write(repo.Name);
    
  3. Uygulamayı çalıştırın.

    Çıkış aynıdır.

Kodu yeniden düzenleme

ProcessRepositoriesAsync yöntemi zaman uyumsuz çalışmayı yapabilir ve depoların koleksiyonunu döndürebilir. bu yöntemi döndürecek Task<List<Repository>>şekilde değiştirin ve konsola yazan kodu çağıranın yanına taşıyın.

  1. sonucu nesne listesi olan bir görevi döndürmek için imzasını ProcessRepositoriesAsyncRepository değiştirin:

    static async Task<List<Repository>> ProcessRepositoriesAsync(HttpClient client)
    
  2. JSON yanıtını işledikten sonra depoları döndür:

    await using Stream stream =
        await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos");
    var repositories =
        await JsonSerializer.DeserializeAsync<List<Repository>>(stream);
    return repositories ?? new();
    

    Bu yöntemi olarak asyncişaretlediğiniz için derleyici dönüş değeri için nesnesini oluştururTask<T>.

  3. Program.cs dosyasını değiştirin ve sonuçları yakalamak için çağrısının ProcessRepositoriesAsync yerine aşağıdakini yazın ve her depo adını konsola yazın.

    var repositories = await ProcessRepositoriesAsync(client);
    
    foreach (var repo in repositories)
        Console.Write(repo.Name);
    
  4. Uygulamayı çalıştırın.

    Çıkış aynıdır.

Daha fazla özelliği seri durumdan çıkarma

Aşağıdaki adımlar, alınan JSON paketindeki daha fazla özelliği işlemek için kod ekler. Büyük olasılıkla her özelliği işlemek istemezsiniz, ancak birkaç özellik daha eklemek C# dilinin diğer özelliklerini gösterir.

  1. sınıfının içeriğini Repository aşağıdaki record tanım ile değiştirin:

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

    Uri ve int türleri, dize gösterimine ve bu gösterimden dönüştürmeye ilişkin yerleşik işlevlere sahiptir. JSON dize biçiminden bu hedef türlerine seri durumdan kaldırmak için ek kod gerekmez. JSON paketi hedef türe dönüştürülmeyen veriler içeriyorsa, serileştirme eylemi bir özel durum oluşturur.

  2. foreach Özellik değerlerini görüntülemek için Program.cs dosyasındaki döngüsünü güncelleştirin:

    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. Uygulamayı çalıştırın.

    Liste artık ek özellikleri içerir.

Tarih özelliği ekleme

Son gönderme işleminin tarihi JSON yanıtında şu şekilde biçimlendirilir:

2016-02-08T21:27:00Z

Bu biçim Eşgüdümlü Evrensel Saat (UTC) içindir, bu nedenle seri durumdan çıkarmanın sonucu özelliği olan Kind bir DateTime değerdirUtc.

Saat diliminizde temsil edilen bir tarih ve saat almak için özel bir dönüştürme yöntemi yazmanız gerekir.

  1. Repository.cs içinde, tarih ve saatin UTC gösterimi için bir özellik ve yerel saate dönüştürülen tarihi döndüren salt okunur LastPush bir özellik ekleyin; dosya aşağıdaki gibi görünmelidir:

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

    LastPush özelliği, erişimci için getifade gövdeli bir üye kullanılarak tanımlanır. Aksesuar falan yok set . Erişimcinin set atlanması, C# dilinde salt okunur özelliği tanımlamanın bir yoludur. (Evet, C# dilinde yalnızca yazma özellikleri oluşturabilirsiniz, ancak değerleri sınırlıdır.)

  2. Program.cs dosyasına başka bir çıkış deyimi ekleyin: yeniden:

    Console.WriteLine($"Last push: {repo.LastPush}");
    
  3. Uygulamanın tamamı aşağıdaki Program.cs dosyasına benzemelidir:

    using System.Net.Http.Headers;
    using System.Text.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)
    {
        await using Stream stream =
            await client.GetStreamAsync("https://api.github.com/orgs/dotnet/repos");
        var repositories =
            await JsonSerializer.DeserializeAsync<List<Repository>>(stream);
        return repositories ?? new();
    }
    
  4. Uygulamayı çalıştırın.

    Çıkış, her depoya son gönderimin tarih ve saatini içerir.

Sonraki adımlar

Bu öğreticide, web istekleri yapan ve sonuçları ayrıştıran bir uygulama oluşturdunuz. Uygulama sürümünüz artık tamamlanmış örnekle eşleşmelidir.

JSON serileştirmeyi yapılandırma hakkında daha fazla bilgi için bkz. .NET'te JSON'ı seri hale getirme ve seri durumdan çıkarma (hazırlama ve seri durumdan çıkarma).