Webbserverprogrammering 1 · område 5 · v.50–52
Code-first: modell, databas och formulär
Ett kort område som avslutar terminen och binder ihop tre saker som annars lärs var för sig: modellklassen, databastabellen och formuläret. Attributen skrivs en gång på klassen och styr både vad databasen får och vad formuläret släpper igenom. Och det är här område 4 betalar tillbaka: du byter ut hela datalagret bakom gränssnittet, och ingen komponent märker det.
- 22 dec Inlämning 5 – Från modell till databas och formulär, kl 23:59 Repots adress lämnas i itslearning. Samma dag som terminen slutar.
Innehållet prövas i prov 4 på vårterminen, där det byggs vidare med relationer och LINQ. Lämna in och gå på lov.
Tolv steg med all kod, från listan i koden till formuläret som sparar i databasen. Följ den här om du missat ett pass.
Inlämning 5 Från modell till databas och formulärKrav för E, C och A med kryssrutor, och de tre kontrollerna som avgör om inlämningen håller.
Lektion 33 · demo En rad som är hela skillnadenTvå formulär som är identiska utom en rad. Det ena tar emot vad som helst. Sedan: hur du lurar din egen webbläsare och ser att servern håller.
Lektion 34 · terminsavslut Fem områden, en kedjaVad höstens fem områden gjorde möjligt för varandra, och vårens fyra projekt med datum.
1. Fyra 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? |
|---|---|---|---|---|
| 31 | ons 9 dec | 45 min | Code-first: modellen är sanningen. Var tar en ny film vägen? Entiteten
får attribut, och DbContext skrivs. |
Guiden steg 1–3 och begreppen |
| 32 | tis 15 dec | 85 min | Migration och databas. Paketen, anslutningssträngen, frödata, första migrationen – och tabellen öppnas: vad blev av attributen? Tjänsten byter implementation. | Guiden steg 4–9, särskilt steg 8 |
| 33 | ons 16 dec | 45 min | Formulär och validering. EditForm,
DataAnnotationsValidator, och varför serversidesvalidering
alltid krävs. |
Guiden steg 10–12 och en rad som är hela skillnaden |
| 34 | tis 22 dec | 85 min | Färdigställ och lämna in. Sedan terminens fem områden som en kedja, och vårens fyra projekt. | Uppgiften med de tre kontrollerna, och terminen och våren |
2. Det här ska sitta
- Du kan säga vad som är fel med en hårdkodad lista, och att data som försvinner vid omstart är det avgörande skälet.
- Du kan förklara vad code-first betyder och vad motsatsen är.
- Du kan skriva ett valideringsattribut med svenskt
ErrorMessageoch säga vilka två saker som läser det. - Du kan säga skillnaden mellan
migrations addochdatabase update, och vilken av dem som rör databasen. - Du kan öppna den skapade tabellen och peka ut vilka attribut som syns i den och vilka som inte gör det – och vad det betyder för valideringen.
- Du kan säga varför
AddDbContextFactoryoch inteAddDbContext, med område 4:s livstider som argument. - Du kan byta ut tjänstens implementation mot databasen utan att ändra gränssnittet, och säga varför ingen komponent behövde ändras.
- Du kan bygga ett
EditFormoch namnge vadModel,FormName,OnValidSubmitochDataAnnotationsValidatorgör var för sig. - Du kan kringgå din egen klientvalidering och beskriva vad servern svarade.
3. Ett verktyg till
Hittills har du haft två kommandon: dotnet build och
dotnet run. Nu kommer ett tredje, och det har egna fel.
dotnet ef läser dina klasser och skriver databasen
Det körs varken vid bygget eller när sidan öppnas, utan när du själv kör
dotnet ef migrations add eller dotnet ef database update.
Står du i fel mapp, saknas ett paket eller stämmer inte anslutningssträngen får
du veta det där – och applikationen kan mycket väl bygga och starta ändå, mot
en databas som inte finns.
| När | Ser ut som | Exempel |
|---|---|---|
| Bygget | Röd text i editorn, dotnet build misslyckas | Required hittas inte, BL0008 |
| Migrationen | dotnet ef avbryts med ett meddelande | Fel mapp, Design-paketet saknas, anslutningssträngen stämmer inte |
| Sidvisningen | Servern kör. Just den sidan svarar 500 | no such table, delat DbContext |
| Aldrig | Allt fungerar. Beteendet är ändå fel | Betyg 99 sparas – DataAnnotationsValidator saknas |
Två vanor som gör hela skillnaden i det här området:
- Kör
dotnet ef database updateefter varje ny migration.addskriver bara en fil. Databasen ändras inte förränupdatekörs. - Testa formuläret med värden som ska vara omöjliga. Ett formulär som bara testats med rätt värden har inte testats. Se hur du kringgår klientvalideringen.
4. Kom igång
Du börjar inte om. Området bygger vidare på projektet från område 4.
| Steg | Det du gör |
|---|---|
| 1 | Öppna ditt projekt från område 4 och kontrollera att listsidan och detaljsidan fungerar med dotnet run. Utan tjänsten bakom gränssnittet går det inte att följa med – gör klart område 4 först. |
| 2 | Kontrollera att dotnet ef --version svarar. Gör den inte det: dotnet tool install --global dotnet-ef, en gång. |
| 3 | Fyll i högerkolumnen i guidens översättningstabell. Vad heter din entitet, din context, ditt DbSet? |
| 4 | Gå igenom din huvudentitet fält för fält: vilka har en regel? Det är de som ska ha attribut. |
| 5 | Lämna den hårdkodade listan kvar tills tjänsten läser ur databasen. Radera den sedan – bygget blir din kontroll. |
Mappstrukturen du är på väg mot:
DittProjekt/
├── Components/
│ └── Pages/
│ └── NyPost.razor formuläret som skapar
├── Data/
│ └── DittProjektContext.cs DbContext med ett DbSet
├── Migrations/ genererad – redigeras aldrig för hand
├── Models/
│ └── DinEntitet.cs klassen, nu med attribut
├── Services/
│ ├── IDinService.cs samma som i område 4, plus metoden som sparar
│ └── DinService.cs läser ur databasen
├── appsettings.json anslutningssträngen
├── dittprojekt.db databasen – ligger i .gitignore
└── Program.cs AddDbContextFactory
Committa efter varje pass. Deadline är tisdag 22 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 migrationen eller vid sidvisningen – leta på rätt ställe.
18 rader
| Symptom | När | Trolig orsak | Åtgärd |
|---|---|---|---|
The type or namespace name 'Required' could not be found | bygget | using-raden saknas | using System.ComponentModel.DataAnnotations; överst i modellklassen. |
The type or namespace name 'DbContext' could not be found | bygget | EF Core-paketen är inte hämtade | dotnet add package Microsoft.EntityFrameworkCore.Sqlite och .Design. |
BL0008 | bygget | [SupplyParameterFromForm] på en egenskap med initierare | Ta bort = new(). Skapa objektet i OnInitialized med ??=. |
dotnet ef känns inte igen | migrationen | Verktyget är inte installerat | dotnet tool install --global dotnet-ef, en gång per dator. |
No project was found | migrationen | Du står i fel mapp | cd till mappen med .csproj. |
Your startup project doesn't reference Microsoft.EntityFrameworkCore.Design | migrationen | Bara ett av de två paketen är hämtat | Båda behövs. dotnet add package Microsoft.EntityFrameworkCore.Design. |
Unable to create a 'DbContext' of type | migrationen | Anslutningssträngen hittas inte | Nyckeln i GetConnectionString måste stämma bokstav för bokstav med appsettings.json. |
The model for context has pending changes | migrationen | Klassen är ändrad efter senaste migrationen | dotnet ef migrations add NamnPaAndringen, sedan database update. |
SQLite Error 1: 'no such table: Filmer' | sidvisning | Migrationen är skriven men inte körd | dotnet ef database update. add räcker inte. |
A second operation was started on this context instance | sidvisning | Ett delat DbContext – AddDbContext i stället för fabriken | AddDbContextFactory, och ett eget context per metod med using. |
Cannot consume scoped service 'DittProjektContext' from singleton | serverstart | Contextet injicerat i en singleton | Samma fel som i område 4. Använd fabriken. |
| Sidan svarar 400 på formuläret | sidvisning | Antiforgery-token saknas – formuläret är byggt för hand | EditForm lägger in den själv. Kontrollera i sidkällan att __RequestVerificationToken finns. |
| Formuläret gör ingenting | sidvisning | FormName saknas | EditForm behöver den vid statisk serverrendering. |
NullReferenceException i markupen | sidvisning | Objektet skapas aldrig | Film ??= new Film(); i OnInitialized. |
OnValidSubmit körs aldrig | aldrig | Något fält validerar inte, och du ser inte vilket | Lägg till <ValidationSummary /> och läs vad som står. |
| Ogiltiga värden sparas | aldrig | <DataAnnotationsValidator /> saknas, eller OnSubmit i stället för OnValidSubmit | Båda behövs. Utan validatorn läses inga attribut; med OnSubmit sparas allt. |
| Felmeddelanden på engelska | aldrig | ErrorMessage saknas på attributet | Skriv den, på svenska, på varje attribut. |
| Sidan visar noll poster | aldrig | Databasen är tom – frödata glömd, eller databasen skapad före den | Radera .db-filen och kör database update igen. |
6. Orden
Orden nedan används från och med nu utan förklaring. Träna tills du kan dem – prov 4 i mars frågar efter flera av dem i klartext.
Ordträning
| Ord | Betyder |
|---|---|
| code-first | Klassen skrivs först, databasen byggs efter den. Motsatsen är database-first. |
| entitet | En klass som motsvarar en tabell. Varje objekt är en rad. |
| attribut | En regel skriven inom hakparenteser ovanför en egenskap: [Required], [Range]. Information, inte kod som körs. |
| data annotations | Samlingsnamnet för valideringsattributen. Namnrymden System.ComponentModel.DataAnnotations. |
| DbContext | Klassen som håller ihop entiteterna och kopplingen till databasen. En session mot databasen. |
| DbSet<T> | En tabell, sedd från C#. Egenskapens namn blir tabellnamnet – därför plural. |
| primärnyckel | Kolumnen som identifierar raden. Id blir det automatiskt. |
| anslutningssträng | Texten som säger var databasen finns. Ligger i appsettings.json, inte i koden. |
| migration | En genererad beskrivning av hur databasen ska ändras. Redigeras aldrig för hand. |
| migrations add | Skriver en ny migrationsfil ur skillnaden mellan klasserna och förra migrationen. Rör inte databasen. |
| database update | Kör de migrationer som inte körts. Det är den som rör databasen. |
| frödata | Rader som följer med migrationen in i databasen. Seed. HasData i OnModelCreating. |
| SQLite | En databas som är en enda fil. Ingen server, inget lösenord – och ingen längd på TEXT. |
| IDbContextFactory | Fabriken som ger varje metod ett eget context. Ett delat DbContext är inte trådsäkert. |
| EditForm | Blazors formulär, som kan validera mot en modell. Lägger in antiforgery-token själv. |
| DataAnnotationsValidator | Komponenten som läser attributen på modellen. Utan den valideras ingenting. |
| OnValidSubmit | Körs bara när valideringen gick igenom. OnSubmit körs oavsett. |
| klientvalidering | Kontroller som körs i webbläsaren. För användarens skull – inte ett skydd. |
| serversidesvalidering | Kontrollen som körs på servern efter att formuläret kommit in. Den enda som går att lita på. |