Grafikus C# – Windows Forms tanfolyam › 15.6 lecke Továbbtanulás · 15.6 lecke · hálózat A 15.5 leckében láttad a webes szolgáltatás (API) oldalát. Most a kliens oldalon dolgozunk: a Windows Forms programod hívja az API-t, és megjeleníti az eredményt. Ez a hibrid megoldás: megvan az asztali program kényelme, az adat pedig közös, a szerveren él. A feladat első ránézésre egyszerű (Webszolgáltatások használata grafikus programból
HttpClient, JSON), a nehézség a valós hálózat: a kapcsolat lassú lehet, megszakadhat, a szerver hibát adhat, a felület közben nem fagyhat le. Ebben a leckében megtanulod az HttpClient helyes használatát, a JSON feldolgozását, az async/await alkalmazását a Formban, a szolgáltatás-osztályt és az interface-t, az időtúllépést és a megszakítást, a hibakezelést, és a nyilvános API-k használatának szabályait.
A lecke végére
- használod az
HttpClientet (egy példány,BaseAddress,Timeout) a szolgáltatás hívására; - JSON-t olvasol és küldesz (
GetFromJsonAsync,PostAsJsonAsync); - a hívást
async/awaitsegítségével úgy végzed, hogy a felület nem fagy le; - szolgáltatás-osztályt és interface-t írsz (12.8 lecke), amely mögé a hálózat rejtőzik;
- kezeled az időtúllépést, a megszakítást, a hálózati és a szerverhibát;
- betartod a nyilvános API-k használatának szabályait (kulcs, kvóta, feltételek, adatvédelem).
Mielőtt elkezded
Ehhez a leckéhez a 15.5 lecke (API és HTTP), a 11. fejezet (async/await), a 10. fejezet (JSON), a 12.8 lecke (szolgáltatás és interface) és a 13.6 lecke (kivételek) szükséges.
HttpClient: a kérés elküldése és a válasz feldolgozása
// EGYETLEN példány az egész programban: az HttpClient-et nem hozzuk létre minden híváshoz (kapcsolatok fogynak el), és nem using-gal
private static readonly HttpClient kliens = new HttpClient
{
BaseAddress = new Uri("https://localhost:5001/"),
Timeout = TimeSpan.FromSeconds(10) // időtúllépés: különben a kérés akár perceket is várhat
};
// OLVASÁS: a válasz JSON-ját közvetlenül objektumokká (lista) alakítja
List<Diak> lista = await kliens.GetFromJsonAsync<List<Diak>>("api/diakok");
// LÉTREHOZÁS: az objektumot JSON-ként elküldi; a választ külön vizsgáljuk
HttpResponseMessage valasz = await kliens.PostAsJsonAsync("api/diakok", new { nev = "Anna" });
if (valasz.IsSuccessStatusCode) // 200–299 közötti állapotkód
{
Diak uj = await valasz.Content.ReadFromJsonAsync<Diak>();
}
else
{
string uzenet = await valasz.Content.ReadAsStringAsync(); // a szerver hibaüzenete (például 400-as válasz szövege)
// az állapotkód: (int)valasz.StatusCode
}
// TÖRLÉS
HttpResponseMessage torles = await kliens.DeleteAsync("api/diakok/3");HttpClient a háttérben kapcsolatokat tart nyitva és újrahasznál. Ha minden híváshoz újat hozol létre (és eldobod), a gép kifogyhat a hálózati kapcsolatokból (socket exhaustion). Egy static readonly példány vagy a IHttpClientFactory a helyes megoldás. Ez ritka kivétel a „mindent using-gal zárj” szabály alól (13.9 lecke).BaseAddress után csak a relatív útvonalat adod meg ("api/diakok", a BaseAddress végén legyen /). A Timeout alapja 100 másodperc, ami egy felületi programban túl hosszú: állíts be néhány másodpercet.System.Net.Http.Json bővítések (GetFromJsonAsync, PostAsJsonAsync, ReadFromJsonAsync) a 10. fejezet System.Text.Json kezelését használják: a mezőnevek megfeleltetése alapból kis-nagybetű-függetlenül működik a webes (JsonSerializerDefaults.Web) beállítással, ezért a nev a Diak.Nev tulajdonságba kerül.HttpClient a 400-as és 500-as válaszra nem dob kivételt (csak hálózati hibára): a IsSuccessStatusCode vagy az EnsureSuccessStatusCode() (az utóbbi kivételt dob) vizsgálja a sikert. A GetFromJsonAsync viszont kivételt dob, ha a válasz nem sikeres.Jósolj!
A szerver 400-as állapotkódot és hibaüzenetet ad (üres név). A kódod PostAsJsonAsync-et hív, és a választ nem vizsgálja. Mit gondol a felhasználó?
Jóslat ellenőrzése
Hogy sikerült a mentés: az HttpClient nem dob kivételt a 400-as válaszra, a program tovább fut, de az adat nem került be. Mindig vizsgáld a választ (IsSuccessStatusCode), és jelezd a felhasználónak a szerver üzenetét.
Szolgáltatás-osztály és interface: a hálózat elrejtése
// 1. Az interface: a Form ezt látja (12.8 lecke), nem az HttpClient-et
public interface IDiakApi
{
Task<List<Diak>> ListazAsync(CancellationToken ct = default);
Task<Diak> UjAsync(string nev, CancellationToken ct = default);
Task TorolAsync(int id, CancellationToken ct = default);
}
// 2. Saját kivétel: a hálózati/szerver hibákat EGY típusba fordítjuk, a Form-nak ennyit kell kezelnie
public class ApiHibaException : Exception
{
public bool Ujraprobalhato { get; } // hálózati/időtúllépés: érdemes újra; 400-as: nem
public ApiHibaException(string uzenet, bool ujraprobalhato, Exception belso = null) : base(uzenet, belso) { Ujraprobalhato = ujraprobalhato; }
}
// 3. A megvalósítás
public class DiakApiKliens : IDiakApi
{
private readonly HttpClient kliens;
public DiakApiKliens(HttpClient kliens) { this.kliens = kliens; } // kívülről kapja: tesztelhető (13.8 lecke)
public async Task<List<Diak>> ListazAsync(CancellationToken ct = default)
{
return await Vegrehajt(async () => await kliens.GetFromJsonAsync<List<Diak>>("api/diakok", ct) ?? new List<Diak>());
}
public async Task<Diak> UjAsync(string nev, CancellationToken ct = default)
{
return await Vegrehajt(async () =>
{
HttpResponseMessage v = await kliens.PostAsJsonAsync("api/diakok", new { nev }, ct);
if (!v.IsSuccessStatusCode) { throw new ApiHibaException(await v.Content.ReadAsStringAsync(), false); } // a szerver üzenete
return await v.Content.ReadFromJsonAsync<Diak>(ct);
});
}
public async Task TorolAsync(int id, CancellationToken ct = default)
{
await Vegrehajt(async () =>
{
HttpResponseMessage v = await kliens.DeleteAsync("api/diakok/" + id, ct);
if (v.StatusCode == HttpStatusCode.NotFound) { throw new ApiHibaException("A diák már nem létezik (valaki más törölte).", false); }
if (!v.IsSuccessStatusCode) { throw new ApiHibaException("A törlés nem sikerült (" + (int)v.StatusCode + ").", true); }
return true;
});
}
// KÖZPONTI hibakezelés: minden hálózati hibát ApiHibaException-né alakít
private async Task<T> Vegrehajt<T>(Func<Task<T>> muvelet)
{
try { return await muvelet(); }
catch (ApiHibaException) { throw; } // már a mi hibánk: tovább
catch (TaskCanceledException ex) when (!ex.CancellationToken.IsCancellationRequested) { throw new ApiHibaException("A szerver nem válaszolt időben.", true, ex); } // időtúllépés
catch (HttpRequestException ex) { throw new ApiHibaException("Nem érhető el a szerver. Ellenőrizd a hálózatot.", true, ex); }
catch (JsonException ex) { throw new ApiHibaException("A szerver váratlan választ adott.", false, ex); }
// a felhasználó általi megszakítás (OperationCanceledException) átmegy: a Form külön kezeli
}
}IDiakApi-t ismeri: a hálózat a megvalósításban van. Teszteléskor egy hamis (FakeDiakApi) osztály adhatja az adatot szerver nélkül (13.8 lecke), és később a megvalósítás (HTTP helyett fájl vagy adatbázis) cserélhető a Form módosítása nélkül.HttpRequestException, időtúllépés, JSON hiba, szerverüzenet). A szolgáltatás ezeket egyetlen ApiHibaException-né alakítja érthető üzenettel: a Formnak elég egyet elkapnia, és a felhasználó nem technikai szöveget lát (13.4 lecke).HttpClient.Timeout lejártakor TaskCanceledException keletkezik, akárcsak a felhasználói megszakításnál (CancellationToken). A ex.CancellationToken.IsCancellationRequested vizsgálat különbözteti meg: ha a felhasználó nem kérte, akkor időtúllépés.Ujraprobalhato jelzi, hogy érdemes-e újra megpróbálni (ideiglenes hálózati hiba), vagy sem (hibás adat, 400-as válasz). Ezt a Form Újra gombja használhatja; automatikus újrapróbáláskor növekvő várakozással és korlátozott számú alkalommal tedd.Jósolj!
A szerver leáll, a felhasználó a Frissítés gombra kattint. A szolgáltatás HttpClient.Timeout értéke az alapértelmezett 100 másodperc. Mit tapasztal a felhasználó?
Jóslat ellenőrzése
Attól függ, hogyan áll a kapcsolat: ha a szerver gép elérhető, de nem válaszol, a kérés akár 100 másodpercig várhat, mielőtt hibát jelezne (a gomb tiltva, a felület „semmit sem csinál”). Ha a gép nem elérhető, hamarabb jön a hálózati hiba. Állíts be rövid Timeout-ot (5–10 mp), jelezz folyamatban állapotot, és kínálj Megszakítás gombot.
A Form oldala: nem fagy le, nem omlik össze
private readonly IDiakApi api;
private CancellationTokenSource megszakitas; // a futó művelet megszakításához
public Form1(IDiakApi api) { InitializeComponent(); this.api = api; }
private async void Form1_Shown(object sender, EventArgs e) { await Frissit(); }
// EGY segéd, amely minden hálózati műveletet körbevesz: tiltás, állapot, hibakezelés, megszakítás
private async Task Fut(Func<CancellationToken, Task> muvelet, string folyamatban)
{
Foglalt(true, folyamatban);
using (megszakitas = new CancellationTokenSource())
{
try { await muvelet(megszakitas.Token); }
catch (OperationCanceledException) { tsslUzenet.Text = "Megszakítva."; }
catch (ApiHibaException ex)
{
tsslUzenet.Text = ex.Message;
btnUjra.Visible = ex.Ujraprobalhato; // csak ideiglenes hibánál kínálunk újrapróbálást
// a részleteket naplózd: naplo.Hiba("API hiba", ex); (13.7 lecke)
}
}
megszakitas = null;
Foglalt(false, null);
}
private void Foglalt(bool foglalt, string uzenet)
{
btnFrissit.Enabled = btnUj.Enabled = btnTorol.Enabled = !foglalt;
btnMegse.Enabled = foglalt;
UseWaitCursor = foglalt;
if (uzenet != null) { tsslUzenet.Text = uzenet; }
if (foglalt) { btnUjra.Visible = false; }
}
private Task Frissit() { return Fut(async ct => { dgvDiakok.DataSource = await api.ListazAsync(ct); tsslUzenet.Text = "Betöltve."; }, "Betöltés..."); }
private async void btnUj_Click(object sender, EventArgs e)
{
string nev = txtNev.Text.Trim();
if (nev.Length == 0) { tsslUzenet.Text = "Add meg a nevet."; return; } // gyors helyi ellenőrzés (a szerver is ellenőriz!)
await Fut(async ct => { await api.UjAsync(nev, ct); txtNev.Clear(); dgvDiakok.DataSource = await api.ListazAsync(ct); }, "Mentés...");
}
private async void btnTorol_Click(object sender, EventArgs e)
{
Diak d = dgvDiakok.CurrentRow?.DataBoundItem as Diak;
if (d == null) { tsslUzenet.Text = "Előbb jelölj ki egy diákot."; return; }
await Fut(async ct => { await api.TorolAsync(d.Id, ct); dgvDiakok.DataSource = await api.ListazAsync(ct); }, "Törlés...");
}
private void btnMegse_Click(object sender, EventArgs e) { megszakitas?.Cancel(); }
private async void btnUjra_Click(object sender, EventArgs e) { await Frissit(); }
// Program.cs: összeállítás (composition root, 12.9 lecke)
var http = new HttpClient { BaseAddress = new Uri("https://localhost:5001/"), Timeout = TimeSpan.FromSeconds(8) };
Application.Run(new Form1(new DiakApiKliens(http)));await alatt a felületi szál szabad marad (11. fejezet): az ablak mozgatható, a Megszakítás gomb működik. A válasz megérkezése után a kód a felületi szálon folytatódik, ezért közvetlenül frissítheted a vezérlőket (Invoke nem kell).async void csak az eseménykezelő szintjén megengedett (11.6 lecke): a Fut kezeli a hibát, így nem szökik ki kezeletlen kivétel.Jósolj!
A felhasználó a Frissítés gomb nyomása után azonnal újra rákattint, mielőtt az első kérés befejeződne (a gombot nem tiltottad le). Mi történhet?
Jóslat ellenőrzése
Két kérés fut egyszerre; az eredmények bármilyen sorrendben érkezhetnek, és a régebbi válasz felülírhatja az újabbat (versenyhelyzet a felületen). A művelet idejére tiltsd a gombokat (Foglalt(true)), vagy az előző kérést szakítsd meg, mielőtt az újat indítod.
Nyilvános API-k használata: a játékszabályok
| Szempont | Mire figyelj? |
|---|---|
| Feltételek és licenc | Minden API-nak van használati feltétele (mire használható, kell-e hivatkozni, kereskedelmi használat). Olvasd el, mielőtt a programodba építed. |
| API-kulcs | Sok szolgáltatás kulcsot ad. A kulcs titok: nem kerül a forráskódba és a verziókezelőbe (15.5 lecke), hanem beállításba vagy környezeti változóba (14.7 lecke). Asztali programban a kulcsot a felhasználó is kiolvashatja: nyilvános programba soha ne tegyél fizetős vagy veszélyes kulcsot. |
| Kvóta és sebességkorlát | A szolgáltató korlátozza, hány kérést küldhetsz percenként/naponta; túllépéskor 429 állapotkód érkezik. Ne kérdezz ciklusban és feleslegesen: gyorsítótárazz, és várj a korlát szerint. |
| Csak HTTPS | Titkosítatlan kapcsolaton a kulcs és az adat lehallgatható. Ellenőrizd, hogy a cím https. |
| Adatvédelem | Ha személyes adatot küldesz egy külső szolgáltatónak, az adat elhagyja a felhasználó gépét: tájékoztasd, és csak a szükségeset küldd. Iskolai környezetben ne küldj valódi diákadatot külső szolgáltatásnak. |
| Változás és megszűnés | A külső API megváltozhat vagy megszűnhet: legyen tartalék viselkedés (gyorsítótár, érthető üzenet), és az API-hívás egy osztályban (interface mögött) legyen, hogy könnyen cserélhető legyen. |
| Hitelesség | A külső adat nem feltétlenül hibátlan vagy megbízható: ellenőrizd a bemenetet (13.5 lecke), és ne bízz meg vakon benne (például ne jeleníts meg HTML-ként). |
FakeDiakApi), vagy egy hamis HttpMessageHandler-t, amely előre megadott választ ad: gyors, megismételhető, nem fogyaszt kvótát.503) az újrapróbálás hasznos, de korlátozott számban és növekvő várakozással (1, 2, 4 mp): a végtelen, gyors újrapróbálás maga is terheli a szervert.Jósolj!
A programod egy ciklusban minden billentyűleütésnél külön kérést küld egy nyilvános keresőszolgáltatásnak, amelynek percenként 60 kérés a kvótája. Mi történik gyors gépelésnél?
Jóslat ellenőrzése
Gyorsan elfogy a kvóta: a szolgáltatás 429-es hibát ad (vagy letilt). Megoldás: késleltetett keresés (debounce: csak akkor kér, ha a felhasználó egy rövid ideig (~400 ms) nem gépel), a régi kérés megszakítása, és gyorsítótár.
Mit tegyél ide: a Windows Forms diák-kliens a listával, az állapotsorral és a hibaüzenettel (leállított szerver).Javasolt fájlnév: winforms-15-6-kliens.webp · Alt szöveg: A Windows Forms API-kliens
Hibakeresés: te vagy a hibadetektív
Mi a baj, és hogyan javítod?
Gondold végig az okot, és csak utána nyisd le a megoldást.
1. A felület lefagy a hívás alatt
var lista = kliens.GetFromJsonAsync<List<Diak>>("api/diakok").Result; // .Result: blokkolHiba és javítás
A .Result (vagy .Wait()) a felületi szálat blokkolja, és holtpontot (deadlock) is okozhat. Használj await-et, és az eseménykezelőt tedd async void-dá (11. fejezet).
2. A sikertelen mentést a program sikeresnek hiszi
Az üres név mentése után a lista nem változik, de hibaüzenet sincs. A 400-as válaszra az Ok és javítás
HttpClient nem dob kivételt: vizsgáld az IsSuccessStatusCode-ot, és jelezd a szerver üzenetét.
3. A program percekig vár, ha nincs hálózat
A szerver nem elérhető, a felület „lefagyott”. Hosszú (alap 100 mp) Ok és javítás
Timeout és nincs visszajelzés. Állíts be rövid Timeout-ot, jelezz folyamatot, tiltsd a gombokat, és adj Megszakítás gombot.
4. Elfogynak a hálózati kapcsolatok
Hosszabb használat után hálózati hibák jönnek. Minden híváshoz új Ok és javítás
HttpClient jön létre. Egyetlen, megosztott példány vagy IHttpClientFactory.
5. A felhasználó látja a technikai hibaüzenetet
Az ablakban „System.Net.Http.HttpRequestException: ...” jelenik meg. A szolgáltatás nem alakítja át a kivételt. A Ok és javítás
Vegrehajt központi hibakezelő érthető üzenetre fordítja (ApiHibaException), a részleteket a napló kapja (13.7 lecke).
6. A kulcs kikerült a nyilvános kódba
Az API-kulcs a forráskódban van, és a kódot feltöltötték. Azonnal cseréld a kulcsot (a törlés a történetben nem elég); a kulcsot beállításból vagy környezeti változóból olvasd (14.7 lecke); a nyilvános programba ne tegyél fizetős kulcsot.Ok és javítás
Mini projekt: diák-kliens a 15.5 lecke API-jához
Készíts Windows Forms klienst a 15.5 lecke webes szolgáltatásához (DiakWeb), hibatűrő módon:
- Előkészítés: indítsd el a 15.5 lecke API-ját (
dotnet run), jegyezd fel a címét (a port a kimenetben látszik). - Projekt: Windows Forms (
DiakKliens); vezérlők:dgvDiakok,txtNev,btnUj,btnTorol,btnFrissit,btnMegse,btnUjra, állapotsor (tsslUzenet). - Modell és interface:
Diak,IDiakApi,ApiHibaException(a leckéből). - Szolgáltatás:
DiakApiKliensa központiVegrehajthibakezeléssel; a cím a beállításból (Beallitasok, 14.7 lecke), nem beégetve. - Form: a
Futsegéddel:Foglaltállapot, megszakítás,asynckezelők; az indításkor automatikus betöltés. - Hibatesztek: (a) üres név (a szerver 400-ast ad: az üzenet jelenjen meg); (b) nem létező azonosító törlése (másik ablakból töröld előbb); (c) a szerver leállítva (érthető üzenet, Újra gomb); (d) lassú válasz (a szerver
Task.Delay(15000)késleltetéssel: a Timeout 8 mp és a Megszakítás gomb); (e) hibás JSON-válasz. - Naplózás: a kérések és hibák naplózása (13.7 lecke), személyes adat nélkül; az időtartam mérésével (
Stopwatch). - Gyorsítótár (extra): az utolsó sikeres lista mentése fájlba (14.7 lecke); a szerver leállásakor a gyorsítótár tartalmának megjelenítése „Nem friss adat” jelzéssel.
- Teszt:
FakeDiakApiosztály, amely a szerver nélkül adja az adatokat; a Form működésének és a hibakezelésnek az ellenőrzése vele (13.8 lecke).
Megoldás megnyitása (próbáld ki előbb önállóan!)
// ---- FakeDiakApi: hálózat nélküli megvalósítás a teszthez és a demóhoz ----
public class FakeDiakApi : IDiakApi
{
private readonly List<Diak> adat = new List<Diak> { new Diak { Id = 1, Nev = "Anna" }, new Diak { Id = 2, Nev = "Béla" } };
public bool Hibazzon { get; set; } // a teszt ezzel váltja ki a hibát
private int kovetkezo = 3;
public async Task<List<Diak>> ListazAsync(CancellationToken ct = default)
{
await Task.Delay(300, ct); // a hálózat lassúságának szimulálása
if (Hibazzon) { throw new ApiHibaException("Nem érhető el a szerver. Ellenőrizd a hálózatot.", true); }
return adat.ToList();
}
public Task<Diak> UjAsync(string nev, CancellationToken ct = default)
{
if (string.IsNullOrWhiteSpace(nev)) { throw new ApiHibaException("A név kötelező, legfeljebb 40 karakter.", false); }
Diak d = new Diak { Id = kovetkezo++, Nev = nev.Trim() };
adat.Add(d);
return Task.FromResult(d);
}
public Task TorolAsync(int id, CancellationToken ct = default)
{
if (adat.RemoveAll(x => x.Id == id) == 0) { throw new ApiHibaException("A diák már nem létezik (valaki más törölte).", false); }
return Task.CompletedTask;
}
}
// ---- a 15.5 API-ban egy LASSÚ végpont a időtúllépés próbájához (csak fejlesztéshez!) ----
app.MapGet("/api/lassu", async () => { await Task.Delay(15000); return Results.Ok(); });
// ---- Gyorsítótár: sikeres lista mentése, hiba esetén visszaolvasása ----
private async Task<List<Diak>> ListaGyorsitotarral(CancellationToken ct)
{
string fajl = Path.Combine(Utak.AdatMappa, "diakok-cache.json"); // az Utak osztály: 14.7 lecke
try
{
List<Diak> friss = await api.ListazAsync(ct);
File.WriteAllText(fajl, JsonSerializer.Serialize(friss));
tsslUzenet.Text = "Betöltve.";
return friss;
}
catch (ApiHibaException ex) when (File.Exists(fajl))
{
tsslUzenet.Text = ex.Message + " Nem friss adatot látsz (gyorsítótár).";
return JsonSerializer.Deserialize<List<Diak>>(File.ReadAllText(fajl)) ?? new List<Diak>();
}
}Várt tapasztalat: a FakeDiakApi szerver nélkül is bemutatja a Formot és a hibakezelést (a Hibazzon igazra állításával a hibaüzenet és az Újra gomb); a /api/lassu végpont a 8 mp-es Timeout miatt „A szerver nem válaszolt időben” üzenetet ad, a Megszakítás gombra az azonnali „Megszakítva.”; a gyorsítótár a szerver leállásakor az utolsó ismert listát mutatja figyelmeztetéssel. A pontos hibaszövegek és időzítések környezetfüggők. A /api/lassu végpontot soha ne hagyd benne az éles szolgáltatásban.
Mit tegyél ide: a kliens normál működés közben, és a „Nem érhető el a szerver” hibaüzenettel az Újra gombbal.Javasolt fájlnév: winforms-15-6-kesz.webp · Alt szöveg: A kész diák-kliens normál és hibás állapotban
Három önálló gyakorlófeladat
Egyszerre csak egyet csinálj: tervezd meg, írd meg, futtasd, ellenőrizd, és csak utána nyisd ki a megoldást.
1. Késleltetett keresés
Írj kereső mezőt, amely csak akkor küld kérést, ha a felhasználó 400 ms-ig nem gépelt, és a régi kérést megszakítja. Egy Egy lehetséges megoldás
System.Windows.Forms.Timer (400 ms), amelyet minden TextChanged újraindít; a Tick eseményben megszakítod az előző CancellationTokenSource-t, újat hozol létre, és hívod az API-t. A kvótát és a felesleges kéréseket így kímélöd.
2. Újrapróbálás növekvő várakozással
Írj segédet, amely ideiglenes hibánál legfeljebb háromszor próbálkozik újra 1, 2, majd 4 másodperc várakozással. Ciklus 0–2: Egy lehetséges megoldás
try a művelet; catch (ApiHibaException ex) when (ex.Ujraprobalhato && kiserlet < 3): await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, kiserlet)), ct); a végén a hiba továbbmegy. A megszakítás (ct) a várakozást is megszakítja.
3. Hamis HttpMessageHandler
Tesztelj a Egy DiakApiKliens-t valódi szerver nélkül.Egy lehetséges megoldás
HttpMessageHandler leszármazott, amelynek SendAsync metódusa előre megadott HttpResponseMessage-et ad (200 és JSON törzs, 400 és szöveg, vagy kivétel); new HttpClient(handler) { BaseAddress = ... } átadható a DiakApiKliens-nek: ellenőrizheted a hibaátalakítást.
Gyakorlótár: 6 további feladat
Három szinten gyakorolhatsz: alap, közepes és kihívás. Csak a próbálkozás után nyisd le a megoldást.
Alap szint
1. Hány HttpClient?
Hány Egyet (vagy HttpClient példányt hozol létre egy programban?Megoldás megnyitása
IHttpClientFactory-t használsz): a kapcsolatok újrahasznosulnak.
2. Mit ad a 400-as válasz?
Dob-e kivételt az Nem (csak hálózati hibára): az HttpClient a 400-as válaszra?Megoldás megnyitása
IsSuccessStatusCode-ot vagy az EnsureSuccessStatusCode()-ot kell használni.
Közepes szint
3. async a Formban
Miért nem szabad Blokkolja a felületet, és holtpontot okozhat; .Result-ot használni a felületi szálon?Megoldás megnyitása
await kell.
4. Időtúllépés
Hogyan különbözteted meg a felhasználói megszakítást az időtúllépéstől? Mindkettő Megoldás megnyitása
TaskCanceledException; ha a saját CancellationToken megszakítást kért, akkor felhasználói megszakítás, különben időtúllépés.
Kihívás szint
5. Interface haszna
Miért kell az A Form nem függ a hálózattól: teszteléskor hamis megvalósítás adható, és a megvalósítás cserélhető a Form módosítása nélkül.IDiakApi a Formnak?Megoldás megnyitása
6. Kvóta
Mit teszel, ha a szolgáltatás 429-et ad? Csökkented a kérések számát (gyorsítótár, késleltetett keresés), és a megadott várakozás után próbálod újra; ha a válasz tartalmaz újrapróbálási időt (Megoldás megnyitása
Retry-After), annyit vársz.
Gyors önellenőrzés
Válaszolj fejben, és csak utána nyisd le a választ. Elküldi a kérést, és a JSON választ közvetlenül objektummá alakítja. Hogy a program ne várjon percekig egy nem válaszoló szerverre. Lehetővé teszi a futó művelet megszakítását (például Megszakítás gombbal). A Formnak egyetlen hibatípust kell kezelnie, érthető üzenettel, és a technikai részletek a naplóba kerülnek. Folyamatban állapotot, tiltott gombokat, várakozó kurzort és Megszakítás gombot. Beállításban vagy környezeti változóban, nem a forráskódban. A kulcsot és a személyes adatot.1. Mit csinál a GetFromJsonAsync?
2. Miért kell Timeout?
3. Mit csinál a CancellationToken?
4. Miért fordítod saját kivételre a hálózati hibákat?
5. Mit mutat a felhasználónak várakozáskor?
6. Hol tartod az API-kulcsot?
7. Mit nem naplózol?
Mit tudsz már?
- Az
HttpClienttel (egy példány,Timeout) JSON-t olvasol és küldesz egy webes szolgáltatásnak. - A hívást
async/await-tel úgy végzed, hogy a felület nem fagy le, és megszakítható. - Szolgáltatás-osztályt és interface-t írsz, amely mögé a hálózat és a hibák rejtőznek.
- Betartod a nyilvános API-k szabályait, és hibatűrő, tesztelhető klienst építesz.
Következő lecke: Önálló záróprojekt ötletek
A tanfolyam zárása: ötletek, értékelési szempontok és útmutató a saját projekted megtervezéséhez.



