Webbserverprogrammering 1 · område 6 · lektion 47–48
Vad prov 4 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. Två av frågetyperna har kod i sig – exemplen nedan är körda.
- 8 mars Projekt 1, kl 23:59 Att göra klart projektet är den bästa förberedelsen som finns.
- 9 mars Prov 4 – databas och datadriven applikation 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.
- Provet täcker område 5 och 6 – databasen från december och allt du byggt sedan dess.
- Koden på provet handlar om en annan applikation än Filmarkivet och än ditt eget projekt. Den är byggd på samma sätt, så du känner igen allt – men svaren går inte att minnas, bara att förstå.
- Kod som är nästan rätt ger poäng. Ett saknat semikolon kostar ingenting.
2. Vad som kommer
| Område | Ungefär | Typiskt innehåll |
|---|---|---|
| Code-first och attribut | 1 fråga | Vad attributen blir i databasen, och vad de bara blir i formuläret |
| Migrationer och relationer | 2 frågor | Befintliga rader och en ny främmande nyckel, ON DELETE CASCADE, Include |
| CRUD och formulär | 3 frågor | Ändringssidans fällor, varför borttagning inte sker på en GET |
| LINQ | 2 frågor | När frågan går till databasen, och vad som görs där och vad som görs i C# |
| Validering | 3 frågor | De tre sorterna, och i vilken ordning de körs |
| Inloggning och behörighet | 3 frågor | Dölja mot skydda, hashning, antiforgery |
| Renderingslägen och lagren | 2 frågor | Varför knapparna inte gör något, varför ingen DbContext i en komponent |
Det här kommer säkert: vad en migration är och varför den inte redigeras
för hand. De tre egenskaperna i en relation, och vad Include gör.
Skillnaden mellan att dölja en länk och att skydda en sida. Varför lösenord
hashas. Och varför knapparna i en QuickGrid inte gör något under
statisk rendering.
Det här kommer inte: inga felmeddelanden att kunna utantill – men du ska kunna säga vad som saknas. Ingen SQL att skriva själv, bara att läsa. Inget om driftsättning eller API:er – det är område 8.
Var görs urvalet? Var hör regeln hemma? Ett ställe utan skäl ger halva poängen. Svaret ska innehålla ett för att, och gärna ett annars.
3. Frågetyp 1 – läs koden: vad hände här?
Koden bygger. Den gör fel sak. Du ska säga vad som händer, och vad som saknas.
@page "/provtraning/o6/1"
@inject IFilmService Arkivet
@* Provträning till prov 4, frågetyp 1: vad hände här? *@
<h1>Provträning 1</h1>
<ul>
@foreach (var film in sidan)
{
<li>@film.Titel</li>
}
</ul>
<p>Sida @Sida av @antalSidor</p>
@code {
[SupplyParameterFromQuery(Name = "sida")]
public int? Sida { get; set; }
private List<Film> sidan = new();
private int antalSidor;
protected override async Task OnParametersSetAsync()
{
List<Film> alla = await Arkivet.HamtaAllaAsync();
antalSidor = (int)Math.Ceiling(alla.Count / 2.0);
int nummer = Sida ?? 1;
sidan = alla.Skip((nummer - 1) * 2).Take(2).ToList();
}
}
Frågan: vad står på sidan för adresserna nedan? Och vad borde koden ha gjort med sidnumret?
| Adress | Vad står på sidan? |
|---|---|
/provtraning/o6/1?sida=2 | |
/provtraning/o6/1?sida=99 | |
/provtraning/o6/1?sida=abc |
?sida=2 ger andra sidan: Rosemarys baby och Såsom i en
spegel, och Sida 2 av 3. ?sida=99 ger en tom lista och
Sida 99 av 3 – inget fel, bara en sida som inte finns.
?sida=abc ger en 500, och den kommer innan en enda rad av
koden körts: ramverket försöker göra om abc till ett
int? och misslyckas.
Full poäng kräver det andra ledet: sidnumret kommer ur adressen, och adressen
kan vem som helst skriva. Det ska läsas som text, tolkas med
int.TryParse och hållas mellan 1 och sista sidan – som i
guidens steg 2.
4. Frågetyp 2 – läs frågan: vad blir SQL:en?
Du får en LINQ-fråga och ska säga vad som görs i databasen och vad som görs i C#. Du skriver ingen SQL själv.
using Filmarkivet.Data;
using Microsoft.EntityFrameworkCore;
namespace Filmarkivet.Services;
// Provträning till prov 4, frågetyp 2: vad blir SQL:en?
public class Topplista
{
private readonly IDbContextFactory<FilmarkivetContext> _fabrik;
public Topplista(IDbContextFactory<FilmarkivetContext> fabrik)
{
_fabrik = fabrik;
}
public async Task<List<string>> HamtaAsync()
{
using var db = await _fabrik.CreateDbContextAsync();
return await db.Filmer
.Where(f => f.Betyg == 5)
.OrderBy(f => f.LangdMinuter)
.Select(f => f.Titel)
.ToListAsync();
}
}
Frågan: vilka kolumner hämtas ur databasen? Var görs urvalet, och var görs sorteringen? I vilken ordning kommer titlarna, med Filmarkivets frödata?
Allt görs i databasen, för att allt ligger på frågan före
ToListAsync. Bara en kolumn hämtas – Titel – för
att Select står före ToListAsync. SQL:en är:
SELECT "f"."Titel"
FROM "Filmer" AS "f"
WHERE "f"."Betyg" = 5
ORDER BY "f"."LangdMinuter"
Filmerna med betyg 5 är Nyckeln till frihet (142 minuter), Sju samurajer (207) och Gökboet (133), och de kommer i längdordning: Gökboet, Nyckeln till frihet, Sju samurajer.
Ett vanligt halvsvar är att Where görs i databasen men
Select i C#. Titta på var ToListAsync står – det är där
frågan går iväg, och allt före den blir SQL.
5. Frågetyp 3 – placera regeln
Du får en regel och ska säga var den hör hemma: ett attribut,
IValidatableObject, eller en kontroll mot databasen.
Och varför.
| Regeln i Filmarkivet | Var? |
|---|---|
| Längden är mellan 1 och 500 minuter | |
| En film med betyget 5 måste ha en beskrivning | |
| Två filmer får inte ha samma titel och samma år | |
| Utgivningsåret får ligga högst två år fram i tiden |
Svara för dig själv innan du klickar på raderna nedan.
| Regeln | Var, och varför |
|---|---|
| Längden 1–500 minuter | Attribut. Ett fält, en fast gräns. [Range]. |
| Betyg 5 kräver beskrivning | IValidatableObject. Två fält tillsammans. Varken betyget eller beskrivningen är fel för sig. |
| Samma titel och år | Mot databasen. Kräver att man vet vad som redan finns. |
| Högst två år fram | Eget attribut. Ett fält – men gränsen beror på vilket år det är, och ett attributs argument måste vara en konstant. Därför inte [Range]. |
6. Frågetyp 4 – motivera valet
Ingen kod att läsa. Du får ett val och ska säga varför det är rätt, eller vad som hade gått fel med ett annat. Så här kan det se ut:
Filmarkivets sökning görs i databasen, men sorteringen i administrationens listvy görs i C#. Varför inte samma ställe för båda?
Sökningen ska fungera också när arkivet är stort, och då ska databasen välja ut raderna i stället för att allt hämtas. Sorteringen ska vara rätt på svenska, och SQLite sorterar gemener efter alla versaler och Ä före Å. Listan är liten, så det kostar lite att sortera den i C#.
Ett svar som bara säger "det är snabbare" ger inga poäng – snabbare för vad, och varför? Full poäng kräver att båda ställena motiveras var för sig.
Fler frågor av samma sort, att öva på:
- Varför är utloggningen en egen endpoint och inte ett formulär på en sida?
- Varför ligger
Includei en egen metod i tjänsten och inte i alla? - Varför ska borttagning ske med en POST från en bekräftelsesida?
- Varför är projektets sidor statiskt renderade, när en
QuickGridfungerar bättre interaktivt?
7. Sexton 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 blir [StringLength(100)] i en SQLite-tabell? | Ingenting. Kolumnen blir TEXT utan längd. Attributet gäller bara i formuläret. |
| Vad är en migration? | En genererad beskrivning av hur databasen ska ändras, räknad fram ur skillnaden mot förra migrationen. |
| Varför redigeras en migration inte för hand? | Den är genererad ur modellen. Ändras den för hand stämmer den inte längre med klassen, och nästa migration räknas fram mot fel utgångsläge. Rätt väg är migrations remove och en ny. |
| Vilka tre egenskaper har en en-till-många-relation, och vilken blir en kolumn? | Den främmande nyckeln och navigationsegenskapen på den ena sidan, listan på den andra. Bara den främmande nyckeln blir en kolumn. |
| Varför avbryts en migration med en ny obligatorisk främmande nyckel, på en databas med egna rader? | De egna raderna får 0 i den nya kolumnen, och det finns ingen kategori med id 0. HasDefaultValue med ett id som finns löser det. |
Vad betyder ON DELETE CASCADE? | Tas kategorin bort, tas alla dess poster bort också. |
Varför är navigationsegenskapen null, fast den främmande nyckeln har ett värde? | Den fylls inte av sig själv. Den måste beställas med Include, och glöms det blir det inget fel – bara tomt. |
Varför ??= och inte = på ändringssidan? | Vid POST har ramverket redan fyllt objektet ur formuläret. = hämtar det gamla ur databasen ovanpå, och ändringen försvinner. |
När går en IQueryable till databasen? | När den körs – vid ToListAsync, FirstOrDefaultAsync, CountAsync och liknande. Allt före det bygger bara på frågan. |
| Varför hittar sökningen i databasen inte alltid svenska ord med andra versaler? | SQLite viker bara A–Z mellan versaler och gemener. Ä och ä är två olika tecken för den. |
| Vilka tre sorters validering finns, och vad ser var och en? | Attribut ser ett fält. IValidatableObject ser hela objektet. En kontroll mot databasen ser det som redan finns. |
Varför körs inte Validate när ett attribut redan sagt nej? | Den körs bara på ett objekt vars fält var för sig är giltiga. Det är ingen mening att jämföra två fält om ett av dem är trasigt. |
Vad är skillnaden mellan AuthorizeView och [Authorize]? | AuthorizeView bestämmer vad som visas. [Authorize] bestämmer vad som går att nå – servern stoppar förfrågan innan sidan körs. |
| Varför lagras inte lösenordet? | Det hashas: görs om till något som går att jämföra med men inte att räkna tillbaka. Den som stjäl databasen får inte lösenorden. |
Skyddar <AntiforgeryToken /> i ett formulär till en egen endpoint? | Bara om endpointen kontrollerar token. Blazors sidor och EditForm gör det själva, app.MapPost gör det inte. |
Varför körs OnInitializedAsync två gånger på en interaktiv sida? | Förrendering. Sidan renderas först statiskt i ett objekt som slängs, och byggs sedan om i ett nytt objekt i kretsen. |
Gör klart Projekt 1. Provet frågar om exakt det du
bygger där – och den som själv sett ändringen försvinna med =
behöver inte plugga på den frågan.