Webbserverprogrammering 1 · område 4 · lektion 29–30
Vad prov 3 prövar
Osäkerhet inför ett prov kostar mer än innehållet. Den här sidan säger vad som kommer, vad som inte kommer, och hur frågorna ser ut. Tre av de fyra frågetyperna har kod i sig – de finns nedan, körda och klara.
- 7 dec Inlämning 4, kl 23:59 Att göra klart uppgiften är den bästa provförberedelsen som finns.
- 8 dec Prov 3 – arkitektur och tjänster 80 minuter, utan dator.
1. Formen
- Åttio minuter. Sluttiden skrivs på tavlan.
- Ingen dator, ingen telefon, inga anteckningar. Papper och penna.
- Sexton frågor. Poängen står vid varje fråga.
- Läs hela provet innan du börjar svara.
- Kod som är nästan rätt ger poäng. Ett gränssnitt med rätt metoder men fel placerat semikolon är värt mer än ett tomt svar.
2. Vad som kommer
| Område | Ungefär | Typiskt innehåll |
|---|---|---|
| Lager och ansvar | 3 frågor | Placera given kod, motivera gränsdragningen |
| Gränssnitt och implementation | 3 frågor | Varför ett gränssnitt, CS0535, byte av implementation |
| Registrering och injektion | 3 frågor | Program.cs, @inject, felet när registreringen saknas |
| Livstider | 4 frågor | De tre, demot, och vad som går fel vid singleton |
| Tillstånd | 2 frågor | Cookie mot session mot singleton |
| Async, loggning, fel | 1 fråga | Task, await, eller try/catch på rätt nivå |
Det här kommer säkert: vad ett gränssnitt lovar. Vad registreringsraden gör. Vad transient, scoped och singleton betyder – och vad scoped faktiskt omfattar vid statisk serverrendering. Var gränsen går mellan komponent och tjänst i given kod.
Det här kommer inte: ingen CSS, inga databaser, ingen Entity Framework, inga metodnamn ur ramverket som inte använts i kursen. Inte heller exakta felmeddelanden ord för ord – men du ska kunna säga när ett fel kommer.
Det är områdets kärna. Ett prov som bara frågar efter definitioner missar precis det som skiljer E från C och A, och därför är minst fyra frågor av typen placera koden eller motivera valet.
På de frågorna räcker det aldrig att skriva vad ett ord betyder. Svaret ska innehålla ett för att och gärna ett annars.
3. Frågetyp 1 – placera koden
Du får en komponent och ska säga vad som hör hemma i tjänsten och vad som ska stanna. Så här kan den se ut:
@page "/provtraning/o4/1"
@inject IFilmService Arkivet
<h1>Provträning 1</h1>
<p>Snittbetyg: @snitt.ToString("0.0")</p>
<ul>
@foreach (var film in tillgangliga)
{
<li>@film.Titel (@film.Ar)</li>
}
</ul>
@code {
private List<Film> tillgangliga = new();
private double snitt;
protected override async Task OnInitializedAsync()
{
List<Film> alla = await Arkivet.HamtaAllaAsync();
int summa = 0;
foreach (var film in alla)
{
summa = summa + film.Betyg;
if (film.Tillganglig)
{
tillgangliga.Add(film);
}
}
snitt = (double)summa / alla.Count;
}
}
Frågan: vilka rader ska flytta till tjänsten, och vilka ska stanna i komponenten? Motivera gränsen med en mening.
Att foreach-loopen, summeringen och urvalet
(if (film.Tillganglig)) ska flytta. Att
.ToString("0.0") och den renderade listan ska stanna.
Full poäng kräver motiveringen: uträkningen och urvalet svarar på vilka och är lika för alla som frågar; antalet decimaler är hur och kan skilja mellan två sidor.
Ett vanligt halvsvar är att flytta allt, inklusive formateringen. Det ger poäng men inte full – tjänsten ska inte bestämma hur något ser ut.
4. Frågetyp 2 – välj livstid
Du får en tjänst och ska välja livstid åt den, med motivering. Klassen:
namespace Filmarkivet.Services.Prov;
// Håller de sökord besökaren har skrivit under sitt besök. Listan ska följa
// besökaren genom hela besöket, och försvinna när besöket är slut.
public class Sokhistorik
{
private readonly List<string> _sokord = new();
public IReadOnlyList<string> Alla => _sokord;
public void LaggTill(string sokord)
{
if (!string.IsNullOrWhiteSpace(sokord))
{
_sokord.Add(sokord);
}
}
}
Och sidan som använder den:
@page "/provtraning/o4/2"
@inject Filmarkivet.Services.Prov.Sokhistorik Historiken
<h1>Provträning 2</h1>
<p>Du har sökt på:</p>
<ul>
@foreach (var ord in Historiken.Alla)
{
<li>@ord</li>
}
</ul>
<form method="get">
<input name="sok" value="@Sok" />
<button type="submit">Sök</button>
</form>
@code {
[SupplyParameterFromQuery(Name = "sok")]
public string? Sok { get; set; }
protected override void OnParametersSet()
{
Historiken.LaggTill(Sok ?? "");
}
}
Frågan: vilken livstid ska Sokhistorik registreras med om
listan ska följa besökaren genom hela besöket? Och vad händer om du väljer fel?
Det närliggande svaret är scoped, för det betyder per besökare. Det är fel på andra ledet, och därför fel på det första.
Vid statisk serverrendering är ett scope en förfrågan. Registrerar du
Sokhistorik som scoped får du ett nytt, tomt objekt vid varje
sidladdning – listan visar bara det senaste sökordet. Registrerar du den som
singleton följer listan inte besökaren utan alla besökare: du ser vad
andra har sökt på.
Rätt svar är att ingen livstid räcker: värdet måste lagras i session,
med tjänsten registrerad som scoped. Det är precis vad
Visningslista gör i guidens steg
13, och vad din egen samling ska göra i inlämningen.
5. Frågetyp 3 – vad hände här?
Du får en sida och en beskrivning av vad som står på skärmen, och ska säga varför. Sidan:
@page "/provtraning/o4/3"
@inject IFilmService Arkivet
<h1>Provträning 3</h1>
<p>Antal filmer i arkivet: @Arkivet.HamtaStatistikAsync()</p>
På skärmen står:
Antal filmer i arkivet: System.Threading.Tasks.Task`1[Filmarkivet.Models.Arkivstatistik]
Frågan: vad har hänt, och hur rättar du det?
Att await saknas: sidan renderade löftet i stället för
svaret. Rättningen är att hämta värdet i
protected override async Task OnInitializedAsync() med
await, spara det i ett fält, och visa fältet.
Lägg märke till att ingenting kraschade. Bygget gav noll varningar, servern startade, sidan svarade 200. Det är ett fel av den fjärde sorten – och det enda spåret är texten på skärmen.
6. Frågetyp 4 – motivera valet
Några meningar om varför något är som det är. Den här typen har ingen kod, och den går inte att plugga in kvällen före – den kräver att du byggt något och tänkt på varför.
Exempel på hur de kan låta:
- Varför ska komponenten injicera gränssnittet och inte klassen, när båda hade fungerat?
- Varför ligger det här området före databasen och inte efter?
- Varför är det ett fel att injicera en scoped tjänst i en singleton? Vad hade gått sönder om ramverket tillåtit det?
- Varför svarar tjänsten med
int?och inte0när registret inte går att nå? - Var ska
try/catchligga, och varför inte i komponenten? - Vad ligger i cookien när du använder session, och vad ligger det inte?
7. Fjorton repetitionsfrågor
Svara högt för dig själv innan du klickar på raden. Att känna igen ett svar är inte samma sak som att kunna det.
| Fråga | Svar |
|---|---|
| Vad är ett gränssnitt? | Ett löfte om vilka metoder som finns, utan att säga hur de utförs. Klassen som står med : IDittService har lovat att hålla det. |
| Vilka tre saker behöver varje tjänst? | Gränssnittet, implementationen och registreringsraden i Program.cs. Den tredje är den som glöms. |
Vad gör raden AddScoped<IDittService, DittService>()? | Säger: ber någon om IDittService, ge dem en DittService, och skapa en ny per förfrågan. |
| Varför ska komponenten injicera gränssnittet och inte klassen? | För att implementationen ska gå att byta utan att komponenten ändras. I område 5 byts hela tjänsten mot en som läser ur en databas. |
Vad betyder CS0535? | Klassen har lovat att uppfylla ett gränssnitt men saknar en av metoderna. Kommer vid bygget. |
| När kommer felet "There is no registered service"? | När sidan öppnas. Bygget går igenom, servern startar – bara den sidan svarar 500. |
| Vad är skillnaden mellan transient, scoped och singleton? | Ett nytt objekt varje gång någon frågar; ett objekt per förfrågan; ett enda objekt för hela servern. |
| Vad omfattar ett scope vid statisk serverrendering? | En förfrågan. Laddar du om sidan är det ett nytt scope och ett nytt objekt – inte ett per besökare. |
| Varför går det inte att injicera en scoped tjänst i en singleton? | Singletonen lever tills servern startas om. Den scoped tjänsten upphör efter förfrågan, och singletonen hade hållit kvar en död referens för alltid. Servern startar inte. |
| Vad betyder att HTTP är tillståndslöst? | Servern minns ingenting mellan två förfrågningar. Varje förfrågan är den första den hört av besökaren. |
| Vad ligger i cookien när du använder session? | Bara nyckeln. Innehållet ligger på servern. Det är därför sessionen försvinner när servern startas om, men cookien finns kvar. |
| Vad händer om en samling registreras som singleton? | Alla besökare delar samma lista. Ingen krasch, inget felmeddelande – det syns bara i ett privat fönster eller när två personer använder sajten samtidigt. |
Varför svarar tjänsten med Task<T> när den inte väntar på något? | För att databasen i område 5 kommer att kräva det. Skrivs metoderna synkrona nu måste varje anropande komponent skrivas om senare. |
Var ska try/catch ligga, och varför? | I tjänsten. Komponenten vet inte vad ett register är och kan inte avgöra vad som är ett rimligt svar när det fattas. Låg det i komponenten måste varje sida upprepa samma felhantering. |
Gör klart inlämningen. Provet frågar om exakt det du bygger där – och den som skrivit sin egen livstidsmotivering behöver inte plugga på den frågan.
Har du tid över: kör övning 65 en gång till och titta på siffrorna. Fyra av sexton frågor handlar om livstider.