Webbserverprogrammering 1 · område 4 · v.46–50
Tjänster, dependency injection och tillstånd
Applikationen ser likadan ut när området är slut. Det är avsikten. Skillnaden ligger i koden: ingen komponent vet längre var data kommer ifrån, uträkningarna har flyttat, och den hårdkodade listan gömmer sig bakom ett gränssnitt. Belöningen kommer i område 5, när databasen byts in bakom samma gränssnitt utan att en enda komponent ändras.
- 7 dec Inlämning 4 – Tjänstelager och tillstånd, kl 23:59 Repots adress lämnas i itslearning.
- 8 dec Prov 3 – arkitektur och tjänster 80 minuter, utan dator. Papper och penna.
Sjutton steg med all kod, från problemet till felhanteringen. Följ den här om du missat ett pass.
Inlämning 4 Tjänstelager och tillståndKrav för E, C och A, med kryssrutor som sparas i din webbläsare.
Övning 51–56 · lektion 24 Gränssnitt och injektionHela kedjan: gränssnittet, implementationen, raden i
Program.cs och @inject.
Konstruktorinjektion, tjänster som använder tjänster, och var gränsen mellan vilka och hur går.
Övning 63–69 · lektion 26–27 Livstider och tillståndTransient, scoped och singleton med egna siffror. Sedan session, och vad som händer med en lista i en singleton.
Övning 70–72 · lektion 28 Async, loggning och felTask hela vägen, strukturerad loggning, och
try/catch på rätt nivå.
Två stoppar bygget, två stoppar sidan, ett stoppar servern och ett säger ingenting alls. Gissa innan du läser rättningen.
Lektion 29–30 Vad provet prövarFördelningen över sexton frågor, tre provfrågor med kod, och fjorton repetitionsfrågor att svara på innan du vänder på svaret.
1. Åtta lektioner
Tisdagarna bär det nya, onsdagarna befäster. Kolumnen längst till höger säger vad du gör om du var borta.
| # | Datum | Längd | Vad vi gör | Missade du passet? |
|---|---|---|---|---|
| 23 | ons 11 nov | 45 min | Varför data inte ska ligga i komponenten. Vad som händer när tre sidor behöver samma lista, och orden för lagren. | Guiden steg 1 och begreppen |
| 24 | tis 17 nov | 85 min | Tjänsteklasser och dependency injection. Gränssnitt, implementation,
registrering och @inject. Områdets tyngsta pass. |
Guiden steg 2–7, sedan övning 51–56 |
| 25 | ons 18 nov | 45 min | Övningspass. Bryt ut en tjänst ur ditt eget projekt, med handledning. | Övning 57–62 |
| 26 | tis 24 nov | 85 min | Livstider. Samma klass registrerad på tre sätt, sida vid sida på
/livstider. |
Guiden steg 8–10, sedan övning 63–66 |
| 27 | ons 25 nov | 45 min | Tillstånd som överlever sidvisningar. HTTP minns ingenting, cookies, session, och formuläret som lägger till. | Guiden steg 11–14 och övning 67–69 |
| 28 | tis 1 dec | 85 min | Asynkron kod, felhantering och loggning. Task,
ILogger och try/catch på rätt
nivå. |
Guiden steg 15–17, sedan övning 70–72 |
| 29 | ons 2 dec | 45 min | Arbetspass och sista finputs. Gränssnitten granskas, livstidsmotiveringen skrivs. | Kravlistan, checklistan och de sex felen |
| 30 | tis 8 dec | 85 min | Prov 3. Skriftligt, 80 minuter, utan dator. | Går inte att ta igen på egen hand – anmäl frånvaron och gör uppsamlingsprovet |
2. Det här ska sitta
- Du kan säga vad ett gränssnitt är och vad det lovar, utan att nämna någon klass.
- Du kan skriva ett gränssnitt, en implementation och registreringsraden – och veta vilken av de tre som glömts när felmeddelandet kommer.
- Du kan förklara varför
@inject IDittServiceär rätt och@inject DittServicefel, även om båda hade fungerat. - Du kan dra gränsen mellan komponent och tjänst i given kod: väljer koden vilka poster som visas hör den till tjänsten, bestämmer den hur de ser ut hör den till komponenten.
- Du kan säga vad transient, scoped och singleton betyder, och vad scoped faktiskt omfattar vid statisk serverrendering.
- Du kan välja livstid åt en given tjänst och motivera valet med vad som gått fel om du valt något annat.
- Du kan förklara varför HTTP är tillståndslöst, och vad en cookie innehåller respektive inte innehåller.
- Du kan säga varför ett
Taskfinns i signaturen redan innan något faktiskt väntar på något. - Du kan säga var
try/catchhör hemma, och vad skillnaden är mellan ett meddelande till användaren och en loggpost till utvecklaren.
3. Felen har fyra tidpunkter
Det här är den enskilt viktigaste skillnaden mot område 3, och det är värt att läsa två gånger.
I område 3 lärde du dig att ett bygge som går igenom inte bevisar något –
felen kom när sidan öppnades. Här tillkommer en tidpunkt till:
registreringarna i Program.cs kontrolleras när servern startar. En
scoped tjänst i en singleton avbryter dotnet run innan servern
hunnit lyssna på en enda förfrågan.
Och en fjärde sort som är värre: felet som inte säger något alls.
| När | Ser ut som | Exempel |
|---|---|---|
| Bygget | Röd text i editorn, dotnet build misslyckas | CS0535, CS0542 |
| Serverstarten | Bygget gick igenom. dotnet run avbryts | Scoped i singleton, AddSession utan cache |
| Sidvisningen | Servern kör. Just den sidan svarar 500 | Oregistrerad tjänst, UseSession glömd |
| Aldrig | Allt fungerar. Beteendet är ändå fel | Samlingen i en singleton – alla besökare delar den |
Tre vanor som gör hela skillnaden i det här området:
- Starta servern efter varje ändring i
Program.cs. Bygget säger ingenting om registreringar. - Läs terminalen där
dotnet runkörs. Både startfelen och loggraderna hamnar där, inte på skärmen. - Öppna ett privat fönster. Det är den enda kontroll som avslöjar den fjärde sorten, och den tar tio sekunder.
De sex felen på egen sida tar ett av varje slag, med rätt meddelande till varje.
4. Kom igång
Du börjar inte om. Området bygger vidare på projektet från område 3.
| Steg | Det du gör |
|---|---|
| 1 | Öppna ditt projekt från område 3 och kontrollera att listsidan och detaljsidan fungerar med dotnet run. |
| 2 | Skapa mappen Services/ bredvid Components/ och Models/. |
| 3 | Fyll i högerkolumnen i guidens översättningstabell. Vad heter ditt gränssnitt, dina metoder, din samling? |
| 4 | Bestäm vilken samling som ska överleva sidvisningar: önskelista, veckomeny, spellista. Den valde du redan när du valde domän. |
| 5 | Lämna den gamla datafilen kvar tills tjänsten fungerar. Radera den sedan – bygget blir din kontroll på att ingen sida smyger tillbaka. |
Mappstrukturen du är på väg mot:
DittProjekt/
├── Components/
│ ├── Pages/ sidorna – visar, beräknar inte
│ └── Delade/ komponenterna från område 3
├── Models/ dina klasser. Datafilen är borta här
├── Services/
│ ├── IDittService.cs löftet
│ ├── DittService.cs klassen som håller det
│ ├── IDinSamling.cs
│ └── DinSamling.cs
└── Program.cs registreringarna
Committa efter varje pass. Deadline är måndag 7 december, och den som committar allt sista kvällen har en historik som inte visar något arbete.
5. Felsökning
Sök på felmeddelandet du fick, eller på ett ord ur det. Kolumnen när säger om felet kommer vid bygget, vid serverstarten eller vid sidvisningen – leta på rätt ställe.
17 rader
| Symptom | När | Trolig orsak | Åtgärd |
|---|---|---|---|
CS0535: does not implement interface member | bygget | Klassen saknar en metod ur gränssnittet | Kopiera signaturen exakt, inklusive Task<>. |
CS0542: member names cannot be the same as their enclosing type | bygget | Injektionsnamnet är samma som filnamnet | Döp om injektionen: Arkivet, inte Filmer, i Filmer.razor. |
CS4033 eller CS4032 kring await | bygget | Metoden är inte async – 4033 om den är void, 4032 om den redan ger Task | async Task på metoden, Task<T> på tjänstens. |
CS1061: 'Task<…>' does not contain a definition for … | bygget | Resultatet används utan await | await före anropet. |
CS0246: The type or namespace name 'IDittService' could not be found | bygget | @using saknas, eller namnrymden i filen stämmer inte med mappen | Lägg @using DittProjekt.Services i _Imports.razor. |
Unable to resolve service for type 'IDistributedCache' | serverstart | AddSession() utan cache | Lägg builder.Services.AddDistributedMemoryCache(); före. |
Cannot consume scoped service 'X' from singleton 'Y' | serverstart | En scoped tjänst injicerad i en singleton | Singletonen lever längre än scopet. Gör den scoped, eller be om tjänsten när den behövs. |
Some services are not able to be constructed | serverstart | Samlingsfelet ovanför – läs det inre undantaget | Meddelandet du behöver står längst ned i högen, inte överst. |
There is no registered service of type 'IDittService' | sidvisning | Tjänsten är inte registrerad | En AddScoped-rad saknas i Program.cs, eller ligger efter builder.Build(). |
There is no registered service of type 'DittService' | sidvisning | @inject mot klassen när registreringen gäller gränssnittet | @inject IDittService. Klassnamnet ska bara stå i sin egen fil och på registreringsraden. |
Session has not been configured for this application or request | sidvisning | app.UseSession() saknas | Lägg till raden bland de övriga app.Use-raderna. |
NullReferenceException i tjänsten | sidvisning | HttpContext är null utanför en förfrågan | _http.HttpContext?.Session med frågetecken. |
| Sidan svarar 400 på formuläret | sidvisning | <AntiforgeryToken /> saknas | Lägg den innanför <form>. |
| Formuläret gör ingenting | sidvisning | @formname eller @onsubmit saknas | Båda behövs. Sidan visas om utan att metoden körts. |
@onclick på knappen | aldrig | Vanan från interaktiva ramverk | Ingenting händer, inget felmeddelande. Använd <form method="post">. |
| Alla besökare ser samma lista | aldrig | Tjänsten är registrerad som singleton | AddScoped plus session. Kontrollera i ett privat fönster. |
| Listan nollställs vid varje sidladdning | aldrig | Scoped, men värdet ligger i ett fält i stället för i session | Vid statisk serverrendering är ett scope en förfrågan. Lägg värdet i session. |
Sidan skriver System.Threading.Tasks.Task`1[…] | aldrig | await saknas | Du renderade löftet i stället för svaret. await i en async-metod. |
6. Orden
Orden nedan används från och med nu utan förklaring. Träna tills du kan dem – provet frågar efter flera av dem i klartext.
Ordträning
| Ord | Betyder |
|---|---|
| lager | En nivå i applikationen med ett eget ansvar: visa, beräkna, lagra. |
| presentationslager | Komponenterna. Visar och tar emot – beräknar inte. |
| tjänst | En klass som gör arbetet: hämtar, räknar, sparar. |
| gränssnitt | Ett löfte om vilka metoder som finns, utan att säga hur de gör. Interface. |
| implementation | Klassen som uppfyller löftet. |
| dependency injection | Att be ramverket om en tjänst i stället för att skapa den själv med new. |
| registrering | Raden i Program.cs som säger vilken klass som svarar på ett gränssnitt. |
| konstruktorinjektion | Att ta emot sina beroenden som parametrar till konstruktorn. |
| @inject | Samma sak i en komponent. Pekar alltid mot gränssnittet, aldrig mot klassen. |
| livstid | Hur länge ett tjänsteobjekt lever. Lifetime. |
| transient | Nytt objekt varje gång någon ber om tjänsten. |
| scoped | Ett objekt per scope. Vid statisk serverrendering är ett scope en förfrågan. |
| singleton | Ett enda objekt för hela servern, delat av alla besökare tills servern startas om. |
| tillstånd | Data som ska finnas kvar mellan två sidvisningar. State. |
| tillståndslös | Att HTTP inte minns något mellan två förfrågningar. Varje förfrågan är den första. |
| cookie | En liten text webbläsaren skickar med varje förfrågan till samma sajt. |
| session | Serverns minne per besökare. Nyckeln till det ligger i en cookie. |
| antiforgery | Skydd mot att en annan sajt skickar ett formulär i besökarens namn. |
| Task<T> | Ett svar som kanske inte är färdigt än. Ett löfte, inte ett värde. |
| await | Vänta tills löftet är infriat, och ge mig innehållet. Kräver async. |
| ILogger | Tjänsten som skriver vad som hände, för utvecklaren – inte för användaren. |
| strukturerad loggning | Att skriva {Id} som parameter i stället för att baka in värdet i strängen. Gör loggen sökbar. |