← Område 4 Övning 70–72 · Async, loggning och fel Avprickning

Webbserverprogrammering 1 · område 4 · lektion 28

Async, loggning och felhantering

Tre övningar, en per tema. De är få men inte små: övning 72 är den som skiljer ett A-arbete från ett C-arbete i den här inlämningen, och den går att göra på en kvart.

Missade du passet?

Lektion 28 var genomgången. Så här tar du igen den, räkna med två timmar:

  1. Läs guidens steg 15. Varför tjänsten svarar med Task redan innan något faktiskt väntar på något.
  2. Läs steg 16 om loggning och steg 17 om felhantering, och skriv av koden.
  3. Kör felhanteringsexemplet från lektionen: /fel-niva och /ratt-niva, med terminalen synlig bredvid webbläsaren. Skillnaden mellan de två sidorna är hela momentet, och den syns till hälften i terminalen.
  4. Lös övning 70 till 72.

Två läsare, två sorters text

Det här området har en enda huvudtanke, och allt annat följer av den:

Undantaget är information till utvecklaren. Det ska loggas i sin helhet. Meddelandet på skärmen är information till användaren. Det ska säga vad som inte gick och vad som fortfarande fungerar.

LoggpostenMeddelandet på skärmen
Läses avDig, kanske månader senareBesökaren, nu
InnehållerHela undantaget, med id och stacktraceVad som saknas och vad som fungerar
HamnarI terminalen där dotnet run körsPå sidan
Får innehållaTekniska detaljerInga klassnamn, inga radnummer

70. Async hela vägen

Medel · tränar: Task<T> från gränssnitt till komponent

Ta en av dina synkrona tjänster och gör hela kedjan asynkron: Task<T> i gränssnittet, Task.FromResult i implementationen, async Task och await i komponenten.

Klart när: projektet bygger utan varningar och sidan visar samma sak som förut.

Det ser onödigt ut, och är det – i dag

Listan ligger i minnet. Svaret är klart direkt. Task.FromResult gör om ett färdigt värde till ett löfte bara för att signaturen kräver det.

Skälet står i område 5: att läsa ur en databas tar tid, och under den tiden ska servern hinna svara andra besökare. Skriver du metoderna synkrona nu måste varje anropande komponent skrivas om när databasen kommer – precis den sortens ändring hela området handlar om att slippa.

Glömmer du ett await kraschar ingenting. Sidan skriver ut löftet i stället för svaret, ungefär så här:

System.Threading.Tasks.Task`1[DittProjekt.Models.DinKlass]

Ser du den raden på en sida vet du precis vad som saknas.

71. Loggning som går att söka i

Medel · tränar: ILogger och strukturerade parametrar

Skriv två loggrader i en tjänst:

_logg.LogWarning($"Hittade inte {id}");
_logg.LogWarning("Hittade inte {Id}", id);

Kör och titta i terminalen. De ser exakt likadana ut – båda skriver Hittade inte 99. Skillnaden finns, men syns inte i den vanliga utskriften.

Byt därför loggaren, tillfälligt, högst upp i Program.cs:

builder.Logging.ClearProviders();
builder.Logging.AddJsonConsole();

Kör om och läs de två raderna igen. Nu ser de ut så här:

{"LogLevel":"Warning","Message":"Hittade inte 99",
 "State":{"{OriginalFormat}":"Hittade inte 99"}}

{"LogLevel":"Warning","Message":"Hittade inte 99",
 "State":{"Id":99,"{OriginalFormat}":"Hittade inte {Id}"}}

Klart när: du kan peka på vad som skiljer dem åt i JSON-utskriften, och säga vad den skillnaden är värd den dag loggen innehåller en miljon rader.

Ta bort de två raderna igen när du är klar – den vanliga utskriften är trevligare att läsa under utveckling.

Varför det spelar roll

I den första raden är 99 en del av texten. I den andra är den ett eget fält med ett namn. Skillnaden är att den andra går att fråga: visa alla varningar där Id är 99. Den första går bara att söka i som text, och en textsökning på 99 träffar allt från radnummer till årtal.

Det är därför alla loggexempel i kursen skriver {Id} som parameter och aldrig bakar in värdet i strängen.

72. Felet som inte får ta ner sidan

Svår · tränar: try/catch i tjänstelagret och returtypen som bär informationen

Gör en tjänst med en metod som alltid kastar ett undantag, och en andra tjänst som anropar den.

Den andra tjänsten ska fånga felet, logga det med LogError, och svara med int?. Sidan ska visa siffran om den finns och ett begripligt meddelande om den inte gör det – utan att svara 500.

Klart när: sidan svarar 200, resten av sidan syns, och hela undantaget står i terminalen.

Fundera sedan på: varför int? och inte 0?

Svaret är den viktigaste raden i hela momentet

Hade metoden lämnat 0 när registret inte svarar hade sidan påstått att noll poster finns – ett faktapåstående som råkar vara falskt. null betyder vet inte, och det är sant.

Och try/catch hör inte hemma i komponenten. Komponenten vet inte vad ett register är och kan därför inte avgöra vad som är ett rimligt svar när det fattas. Tjänsten vet båda delarna – och skulle felhanteringen ligga i komponenten måste varje sida som använder tjänsten upprepa den.

Det är samma argument som hela område 4 vilar på.

Avprickning

Kryssen sparas i din webbläsare.

Lösta övningar i det här temat

Övning 72 är ett A-krav i inlämningen, nästan ord för ord. Gör den, och skriv sedan samma sak i ditt eget projekt.