A REST (Representational State Transfer) API-k segítségével a WPF, Windows Form alkalmazásunk kommunikálhat külső szolgáltatásokkal, adatokat kérhet le (GET), küldhet (POST), módosíthat (PUT), törölhet (DELETE). Ezek a CRUD műveletek, amiket már JS-ben is megnéztünk.
C#-ban a HttpClient osztályt fogjuk használni a HTTP kérések küldésére és fogadására. Ehhez a System.Net.Http névteret kell importálni.
A HttpClient aszinkron metódusokat biztosít a HTTP kérésekhez.
create | PostAsync(uri, content) | Új erőforrás létrehozása, vagy adat küldése |
read | GetAsync(uri) | Adatok lekérése |
update | PutAsync(uri, content) | Frissítés |
delete | DeleteAsync(uri) | Törlés |
Ezek a metódusok egy HttpResponseMessage-et adnak vissza, ami tartalmazza a válasz státuszkódját, fejlécét, törzsét.
Tehát, ha megkaptuk a HttpResponseMessage-et, ellenőrizni célszerű a státusz kódot.
- response.IsSuccessStatusCode: igaz, ha a státuszkód 200-299 közötti érték
- response.StatusCode: a konkrét státuszkód (pl: HttpStatusCode.OK, HttpStatusCode.NotFound, HttpStatusCode.InternalServerError)
A válasz törzse:
- response.Content.ReadAsStringAsync() string-ként
- response.Content.ReadAsByteArrayAsync(): Bájt-tömbként olvassa be.
- response.Content.ReadAsStreamAsync(): Streamként olvassa be.
Adat szerializáció és deszerializáció (JSON/XML)
A REST API-k gyakran JSON vagy XML formátumban küldenek/fogadnak adatokat.
Deszerializáció (válasz törzséből C# objektummá): A válasz string vagy stream tartalmát C# objektumokká kell alakítani.
- System.Text.Json: A .NET Core 3.1+ beépített, nagy teljesítményű JSON szerializálója/deszerializálója. JsonSerializer.Deserialize(jsonString) vagy JsonSerializer.DeserializeAsync(stream).
- Newtonsoft.Json (Json.NET): Nagyon népszerű, rugalmas, harmadik féltől származó könyvtár. JsonConvert.DeserializeObject(jsonString).
Szerializáció (C# objektumból kérés törzsévé): Amikor adatot küldünk (POST, PUT), a C# objektumokat JSON/XML stringgé kell alakítani.
- System.Text.Json: JsonSerializer.Serialize(object).
- Newtonsoft.Json: JsonConvert.SerializeObject(object).
Ehhez szükségünk lesz C# osztályokra, amelyek struktúrája megegyezik az API által használt adatstruktúrával.
Az aszinkron működés fontossága.(async és await): Azért fontos a használatuk, mert a hálózati kérések lassúak lehetnek (ezredmásodpercek vagy akár másodpercek). Ha ezeket szinkron módon hívnánk meg az UI szálon, az alkalmazás lefagyna, nem reagálna, amíg a kérés be nem fejeződik.
Az HttpClient metódusai már aszinkronok! (GetAsync, PostAsync stb.).
1.példa: GetAsync, adatok lekérése

Nézzünk egy példát! A dog.ceo api végpontjáról töltsünk be egy kutyás képet gombnyomásta! Ehhez szükség lesz egy gombra, egy image vezérlőre.
var: automatikusan felveszi azt a típust, amit a jobb oldalon kap
var response = await _httpClient.GetAsync(apiUrl);
HttpResponseMessage response = await _httpClient.GetAsync(apiUrl);
var content = await response.Content.ReadAsStringAsync();
string content = await response.Content.ReadAsStringAsync();
var dogData = JsonSerializer.Deserialize(content);
DogApiResponse dogData = JsonSerializer.Deserialize(content);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
/* MainWindow.xaml */ <Window x:Class="kutyaApi.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="DogAPI" Height="500" Width="400"> <StackPanel Margin="10"> <Button Content="Új kutyus" Click="LoadDogButton_Click" Height="40" Margin="0,0,0,10"/> <Image x:Name="DogImage" Stretch="Uniform" Height="344"/> <Button Content="Kilépés" Background="#FF04650F" Foreground="White" Height="36" Width="222" Click="Button_Click"/> </StackPanel> </Window> /* MainWindows.xaml.cs */ using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System; using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; namespace kutyaApi { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private readonly HttpClient _httpClient = new HttpClient(); public MainWindow() { InitializeComponent(); } private async void LoadDogButton_Click(object sender, RoutedEventArgs e) { try { string apiUrl = "https://dog.ceo/api/breeds/image/random"; var response = await _httpClient.GetAsync(apiUrl); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); // MessageBox.Show(content, "Válasz a szervertől"); //System.Diagnostics.Debug.WriteLine(content); var dogData = JsonSerializer.Deserialize<DogApiResponse>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); MessageBox.Show(dogData?.Message ?? "Nincs link", "Lekért link"); if (dogData?.Message != null) { DogImage.Source = new BitmapImage(new Uri(dogData.Message)); } } catch (Exception ex) { MessageBox.Show("Hiba történt: " + ex.Message); } } private void Button_Click(object sender, RoutedEventArgs e) { this.Close(); } } public class DogApiResponse { public string Message { get; set; } public string Status { get; set; } } } |

2. példa: Rick and Morty – szereplők adatainak lekérése, szintén GetAsync
Ebben a példában a RickAndMorty api-ról fogjuk egy karakter adatait lekérni. Ez a végpont jóval több adatot ad vissza, mint a kutyás példa.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
https://rickandmortyapi.com/api/character/2 { "id": 2, "name": "Morty Smith", "status": "Alive", "species": "Human", "type": "", "gender": "Male", "origin": { "name": "Earth", "url": "https://rickandmortyapi.com/api/location/1" }, "location": { "name": "Earth", "url": "https://rickandmortyapi.com/api/location/20" }, "image": "https://rickandmortyapi.com/api/character/avatar/2.jpeg", "episode": [ "https://rickandmortyapi.com/api/episode/1", "https://rickandmortyapi.com/api/episode/2", // ... ], "url": "https://rickandmortyapi.com/api/character/2", "created": "2017-11-04T18:50:21.651Z" } |
Az ablak felépítése egyszerű, van egy gomb, egy kép, és szöveg blokkok, amelyek megjelenítik az adatokat.
MainWindows.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<Window x:Class="RickAndMorty.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Rick and Morty - Szereplő" Height="550" Width="500"> <StackPanel Margin="10"> <Button Content="Szereplő adatai" Click="LoadCharacterButton_Click" Height="40" Margin="0,0,0,10"/> <Image x:Name="CharacterImage" Height="200" Stretch="Uniform" Margin="0,0,0,10"/> <TextBlock x:Name="NameText" FontSize="16" FontWeight="Bold" Margin="0,0,0,5"/> <TextBlock x:Name="StatusText" FontSize="14" Margin="0,0,0,5"/> <TextBlock x:Name="SpeciesText" FontSize="14" Margin="0,0,0,5"/> <TextBlock x:Name="GenderText" FontSize="14" Margin="0,0,0,5"/> <TextBlock x:Name="EpisodesText" FontSize="14" Margin="0,0,0,5"/> <TextBlock x:Name="OriginText" FontSize="12" Margin="0,0,0,5"/> <TextBlock x:Name="LocationText" FontSize="12" Margin="0,0,0,5"/> </StackPanel> </Window> |
MainWindow.xaml.cs
Az osztály kicsit összetettebb., mint a kutyás példában. Az „origin” és a „location” egy-egy objektum az objektumon belül. Ezeket külön osztályba célszerű tenni. Az „episode” egy tömb, aminek az elemeit hozzáadtam a stringhez a sting.Join() segítségével.
Ennél elegánsabb, ha nem az egész url-t iratjuk ki, hanem csak az epizódok számát. Kommentelt részben látható, az utolsó /-jel utáni számot adom hozzá ebben az esetben a szöveghez.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
using System; using System.Net.Http; using System.Text.Json; using System.Threading.Tasks; using System.Windows; using System.Windows.Media.Imaging; namespace RickAndMorty { public partial class MainWindow : Window { private readonly HttpClient _httpClient = new HttpClient(); public MainWindow() { InitializeComponent(); } private async void LoadCharacterButton_Click(object sender, RoutedEventArgs e) { try { // Véletlenszám generálása 1 és 800 között var random = new Random(); int randomId = random.Next(1, 801); // 1-től 800-ig, 801-et már nem veszi bele //string apiUrl = "https://rickandmortyapi.com/api/character/2"; string apiUrl = $"https://rickandmortyapi.com/api/character/{randomId}"; var response = await _httpClient.GetAsync(apiUrl); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); var character = JsonSerializer.Deserialize<Character>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); // levágjuk a számot a kurva hosszú url végéről // "https://rickandmortyapi.com/api/episode/1", /* var episodeNumbers = character.Episode .Select(url => url.Split('/').Last()) .ToArray(); */ if (character != null) { NameText.Text = $"Név: {character.Name}"; StatusText.Text = $"Állapot: {character.Status}"; SpeciesText.Text = $"Faj: {character.Species}"; GenderText.Text = $"Nem: {character.Gender}"; CharacterImage.Source = new BitmapImage(new Uri(character.Image)); EpisodesText.Text = "Epizódok:\n" + string.Join("\n", character.Episode); //EpisodesText.Text = "Epizódok: " + string.Join(", ", episodeNumbers); OriginText.Text = $"Eredet: {character.Origin.Name}"; LocationText.Text = $"Helyszín: {character.Location.Name}"; } } catch (Exception ex) { MessageBox.Show("Hiba történt: " + ex.Message); } } } public class Character { public int Id { get; set; } public string Name { get; set; } public string Status { get; set; } public string Species { get; set; } public string Type { get; set; } public string Gender { get; set; } public Origin Origin { get; set; } public Location Location { get; set; } public string Image { get; set; } public string[] Episode { get; set; } public string Url { get; set; } public DateTime Created { get; set; } } public class Origin { public string Name { get; set; } public string Url { get; set; } } public class Location { public string Name { get; set; } public string Url { get; set; } } } |
3. példa 10db macskás kép megjelenítése API végpont segítségével

A programunk felülete tartalmazzon egy ScrollViewer-t. Ezen belül hozzunk létre egy gombot, és egy StackPanelt! Ehhez a StackPanel-hez fogjuk hozzáadni a képeket!
MainWindwow.xaml
1 2 3 4 5 6 7 8 9 10 11 |
<Window x:Class="macska_gui.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Macskás képek" Height="600" Width="400"> <ScrollViewer VerticalScrollBarVisibility="Auto" Margin="0,0,0,-70"> <StackPanel Name="ImagePanel" Margin="10" > <Button Content="Új képek betöltése" Click="ReloadImages_Click" Margin="0,0,0,10"/> </StackPanel> </ScrollViewer> </Window> |
A gombunk feladata: képek újratöltése. Ehhez törölni kell az előző adag képet, és betölteni 10db új képet. A gomb működéséért a ReloadImages_Click() eljárás felel.
1 2 |
ImagePanel.Children.RemoveRange(1, ImagePanel.Children.Count - 1); // törli a képeket, a gombot megtartja LoadCatImages(); // új képek betöltése |
Az API egy tömböt, azon belül 10db objektumot ad vissza. Minden objektumnak van 4db adata: id, url, width, height.Ezekből készítünk egy osztályt, mint az eddigi feladatoknál.
LoadCatImages(): mivel 10db adatot kapunk, azokon végig fogunk menni, és hozzáadjuk őket a StackPanelhez (aminek a neve ImagePanel) Nagyon hasonló a metódus, mint JS esetén, gyermek elemeket adunk a szülő elemnek. A képeket BitmapImage()-ként tároljuk.
MainWindows.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
using System; using System.Collections.Generic; using System.Net.Http; using System.Text.Json; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; namespace macska_gui { public partial class MainWindow : Window { private static readonly HttpClient client = new HttpClient(); public MainWindow() { InitializeComponent(); LoadCatImages(); } private void ReloadImages_Click(object sender, RoutedEventArgs e) { ImagePanel.Children.RemoveRange(1, ImagePanel.Children.Count - 1); // törli a képeket, a gombot megtartja LoadCatImages(); // új képek betöltése } private async void LoadCatImages() { try { string url = "https://api.thecatapi.com/v1/images/search?limit=10"; var response = await client.GetStringAsync(url); var images = JsonSerializer.Deserialize<List<CatImage>>(response); foreach (var img in images) { var bitmap = new BitmapImage(); bitmap.BeginInit(); bitmap.UriSource = new Uri(img.url); bitmap.DecodePixelWidth = 300; // 300px széles bitmap.EndInit(); var imageControl = new Image { Source = bitmap, Width = 300, Margin = new Thickness(0, 10, 0, 10) }; ImagePanel.Children.Add(imageControl); } } catch (Exception ex) { MessageBox.Show("Hiba történt: " + ex.Message); } } } public class CatImage { public string id { get; set; } public string url { get; set; } public int width { get; set; } public int height { get; set; } } } |