← Webbserverprogrammering 1 Område 4 · Tjänster, dependency injection och tillstånd Felsökning

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.

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.

#DatumLängdVad vi görMissade du passet?
23ons 11 nov45 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
24tis 17 nov85 min Tjänsteklasser och dependency injection. Gränssnitt, implementation, registrering och @inject. Områdets tyngsta pass. Guiden steg 2–7, sedan övning 51–56
25ons 18 nov45 min Övningspass. Bryt ut en tjänst ur ditt eget projekt, med handledning. Övning 57–62
26tis 24 nov85 min Livstider. Samma klass registrerad på tre sätt, sida vid sida på /livstider. Guiden steg 8–10, sedan övning 63–66
27ons 25 nov45 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
28tis 1 dec85 min Asynkron kod, felhantering och loggning. Task, ILogger och try/catch på rätt nivå. Guiden steg 15–17, sedan övning 70–72
29ons 2 dec45 min Arbetspass och sista finputs. Gränssnitten granskas, livstidsmotiveringen skrivs. Kravlistan, checklistan och de sex felen
30tis 8 dec85 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

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.

Nu kan servern vägra starta

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ärSer ut somExempel
ByggetRöd text i editorn, dotnet build misslyckasCS0535, CS0542
ServerstartenBygget gick igenom. dotnet run avbrytsScoped i singleton, AddSession utan cache
SidvisningenServern kör. Just den sidan svarar 500Oregistrerad tjänst, UseSession glömd
AldrigAllt fungerar. Beteendet är ändå felSamlingen i en singleton – alla besökare delar den

Tre vanor som gör hela skillnaden i det här området:

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.

StegDet du gör
1Öppna ditt projekt från område 3 och kontrollera att listsidan och detaljsidan fungerar med dotnet run.
2Skapa mappen Services/ bredvid Components/ och Models/.
3Fyll i högerkolumnen i guidens översättningstabell. Vad heter ditt gränssnitt, dina metoder, din samling?
4Bestäm vilken samling som ska överleva sidvisningar: önskelista, veckomeny, spellista. Den valde du redan när du valde domän.
5Lä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

SymptomNärTrolig orsakÅtgärd
CS0535: does not implement interface memberbyggetKlassen saknar en metod ur gränssnittetKopiera signaturen exakt, inklusive Task<>.
CS0542: member names cannot be the same as their enclosing typebyggetInjektionsnamnet är samma som filnamnetDöp om injektionen: Arkivet, inte Filmer, i Filmer.razor.
CS4033 eller CS4032 kring awaitbyggetMetoden är inte async – 4033 om den är void, 4032 om den redan ger Taskasync Task på metoden, Task<T> på tjänstens.
CS1061: 'Task<…>' does not contain a definition for …byggetResultatet används utan awaitawait före anropet.
CS0246: The type or namespace name 'IDittService' could not be foundbygget@using saknas, eller namnrymden i filen stämmer inte med mappenLägg @using DittProjekt.Services i _Imports.razor.
Unable to resolve service for type 'IDistributedCache'serverstartAddSession() utan cacheLägg builder.Services.AddDistributedMemoryCache(); före.
Cannot consume scoped service 'X' from singleton 'Y'serverstartEn scoped tjänst injicerad i en singletonSingletonen 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 constructedserverstartSamlingsfelet ovanför – läs det inre undantagetMeddelandet du behöver står längst ned i högen, inte överst.
There is no registered service of type 'IDittService'sidvisningTjänsten är inte registreradEn 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 requestsidvisningapp.UseSession() saknasLägg till raden bland de övriga app.Use-raderna.
NullReferenceException i tjänstensidvisningHttpContext är null utanför en förfrågan_http.HttpContext?.Session med frågetecken.
Sidan svarar 400 på formuläretsidvisning<AntiforgeryToken /> saknasLägg den innanför <form>.
Formuläret gör ingentingsidvisning@formname eller @onsubmit saknasBåda behövs. Sidan visas om utan att metoden körts.
@onclick på knappenaldrigVanan från interaktiva ramverkIngenting händer, inget felmeddelande. Använd <form method="post">.
Alla besökare ser samma listaaldrigTjänsten är registrerad som singletonAddScoped plus session. Kontrollera i ett privat fönster.
Listan nollställs vid varje sidladdningaldrigScoped, men värdet ligger i ett fält i stället för i sessionVid statisk serverrendering är ett scope en förfrågan. Lägg värdet i session.
Sidan skriver System.Threading.Tasks.Task`1[…]aldrigawait saknasDu 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

OrdBetyder
lagerEn nivå i applikationen med ett eget ansvar: visa, beräkna, lagra.
presentationslagerKomponenterna. Visar och tar emot – beräknar inte.
tjänstEn klass som gör arbetet: hämtar, räknar, sparar.
gränssnittEtt löfte om vilka metoder som finns, utan att säga hur de gör. Interface.
implementationKlassen som uppfyller löftet.
dependency injectionAtt be ramverket om en tjänst i stället för att skapa den själv med new.
registreringRaden i Program.cs som säger vilken klass som svarar på ett gränssnitt.
konstruktorinjektionAtt ta emot sina beroenden som parametrar till konstruktorn.
@injectSamma sak i en komponent. Pekar alltid mot gränssnittet, aldrig mot klassen.
livstidHur länge ett tjänsteobjekt lever. Lifetime.
transientNytt objekt varje gång någon ber om tjänsten.
scopedEtt objekt per scope. Vid statisk serverrendering är ett scope en förfrågan.
singletonEtt enda objekt för hela servern, delat av alla besökare tills servern startas om.
tillståndData som ska finnas kvar mellan två sidvisningar. State.
tillståndslösAtt HTTP inte minns något mellan två förfrågningar. Varje förfrågan är den första.
cookieEn liten text webbläsaren skickar med varje förfrågan till samma sajt.
sessionServerns minne per besökare. Nyckeln till det ligger i en cookie.
antiforgerySkydd 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.
awaitVänta tills löftet är infriat, och ge mig innehållet. Kräver async.
ILoggerTjänsten som skriver vad som hände, för utvecklaren – inte för användaren.
strukturerad loggningAtt skriva {Id} som parameter i stället för att baka in värdet i strängen. Gör loggen sökbar.