Webbserverprogrammering 1 · område 5 · lektion 33
En rad som är hela skillnaden
Två formulär som är identiska utom en rad. Det ena tar emot ett tomt namn, 500 biljetter och en e-postadress som inte är en. Det andra stoppar alla tre. Sedan tar du bort spärren i webbläsaren och ser om servern klarar sig utan den.
Det här är lektion 33:s demo, och den går att göra själv på tjugo minuter. I ordning:
- Lägg in de tre filerna nedan i ditt projekt – modellen i
Models/Demo/, formulären iComponents/Pages/. 5 min. - Kör, och skicka samma dåliga värden till båda adresserna. 3 min.
- Gör DevTools-testet på formuläret med validering. 5 min.
- Gör sedan samma test på ditt eget formulär från guidens steg 11. Det är ett C-krav i inlämningen. 5 min.
Demot behöver ingen databas. Har du inte fått migrationen att gå igenom kan du ändå göra det här.
1. Modellen
En anmälan med tre fält och tre regler. Klassen ligger inte i databasen – poängen är enbart valideringen.
using System.ComponentModel.DataAnnotations;
namespace Filmarkivet.Models.Demo;
// Demomodell till lektion 33. Ligger inte i databasen – poängen är enbart
// valideringen.
public class Anmalan
{
[Required(ErrorMessage = "Namnet måste fyllas i.")]
[StringLength(40, ErrorMessage = "Namnet får vara högst 40 tecken.")]
public string Namn { get; set; } = "";
[Range(1, 10, ErrorMessage = "Antalet biljetter är 1 till 10.")]
public int Biljetter { get; set; } = 1;
[EmailAddress(ErrorMessage = "Det där ser inte ut som en e-postadress.")]
public string Epost { get; set; } = "";
}
Tre attribut, tre svenska felmeddelanden. Lägg märke till att de bara
står där. Ingenting i klassen kör dem – de är regler som ligger och
väntar på att någon ska läsa dem. Det var det du såg på lektion 31: du satte
[Required], byggde, och ingenting hände.
2. Två formulär
Först det som saknar valideringen. Det tar emot vad som helst:
@page "/demo/utan-validering"
@using Filmarkivet.Models.Demo
@* Samma formulär som MedValidering.razor – utom en enda rad. *@
<h1>Utan validering</h1>
<EditForm Model="Formular" OnValidSubmit="TaEmot" FormName="utan">
<p><label>Namn<br /><InputText @bind-Value="Formular!.Namn" /></label></p>
<p><label>Antal biljetter<br /><InputNumber @bind-Value="Formular!.Biljetter" /></label></p>
<p><label>E-post<br /><InputText @bind-Value="Formular!.Epost" /></label></p>
<button type="submit">Skicka</button>
</EditForm>
@if (mottagen is not null)
{
<p class="tomt">
Mottaget: <b>@mottagen.Namn</b> · @mottagen.Biljetter biljetter ·
@mottagen.Epost
</p>
}
@code {
[SupplyParameterFromForm]
private Anmalan? Formular { get; set; }
private Anmalan? mottagen;
protected override void OnInitialized()
{
Formular ??= new Anmalan();
}
private void TaEmot()
{
mottagen = Formular;
}
}
Och det som har den:
@page "/demo/med-validering"
@using Filmarkivet.Models.Demo
@* Identisk med UtanValidering.razor, plus DataAnnotationsValidator och
meddelandena. Det är hela skillnaden. *@
<h1>Med validering</h1>
<EditForm Model="Formular" OnValidSubmit="TaEmot" FormName="med">
<DataAnnotationsValidator />
<ValidationSummary />
<p>
<label>Namn<br /><InputText @bind-Value="Formular!.Namn" /></label>
<ValidationMessage For="() => Formular!.Namn" />
</p>
<p>
<label>Antal biljetter<br /><InputNumber @bind-Value="Formular!.Biljetter" /></label>
<ValidationMessage For="() => Formular!.Biljetter" />
</p>
<p>
<label>E-post<br /><InputText @bind-Value="Formular!.Epost" /></label>
<ValidationMessage For="() => Formular!.Epost" />
</p>
<button type="submit">Skicka</button>
</EditForm>
@if (mottagen is not null)
{
<p class="tomt">
Mottaget: <b>@mottagen.Namn</b> · @mottagen.Biljetter biljetter ·
@mottagen.Epost
</p>
}
@code {
[SupplyParameterFromForm]
private Anmalan? Formular { get; set; }
private Anmalan? mottagen;
protected override void OnInitialized()
{
Formular ??= new Anmalan();
}
private void TaEmot()
{
mottagen = Formular;
}
}
Kör, och fyll i samma värden i båda:
| Fält | Skriv |
|---|---|
| Namn | lämna tomt |
| Antal biljetter | 500 |
| E-post | inte-en-adress |
| Adress | Vad som händer |
|---|---|
/demo/utan-validering | Mottaget: · 500 biljetter · inte-en-adress. Allt gick igenom |
/demo/med-validering | Tre felmeddelanden. Ingenting togs emot |
Webbläsaren kan protestera på 500 innan du hinner skicka – InputNumber
renderar type="number". Skicka ändå, eller läs vidare: det är precis
den spärren du snart tar bort.
3. Raden som skiljer
Läs de två filerna bredvid varandra och leta upp skillnaden innan du läser vidare.
Svaret: <DataAnnotationsValidator />. Den syns inte
på skärmen och tar inte emot något värde, och det är därför den är så lätt att
glömma.
Det andra formuläret har också <ValidationSummary /> och tre
<ValidationMessage> – men de visar bara felen. Utan validatorn
finns det inga fel att visa, för ingen har läst attributen.
De gör ingenting av sig själva. DataAnnotationsValidator är den
som läser dem. Tar du bort den raden har du en modell full av regler och ett
formulär som inte känner till en enda av dem.
Och OnValidSubmit hör ihop med den: metoden körs bara när
validatorn sagt att allt är i ordning. Med OnSubmit i stället körs
metoden oavsett – och då har du byggt ett formulär som sparar skräp, med en
validator som bara visar röd text.
4. Kringgå klientvalideringen
Skriv 500 i biljettfältet på /demo/med-validering. Webbläsaren
stoppar dig, eller så gör ValidationSummary det. Det bevisar
ingenting. Allt som händer i webbläsaren är besökarens att stänga av.
Gör så här i stället:
- Öppna
/demo/med-valideringoch tryck F12. - Gå till fliken Elements. Tryck Ctrl+F och sök på
Biljetterför att hitta fältet. - Dubbelklicka på
type="number"och ändra tilltype="text". Finnsminellermax, ta bort dem. - Skriv
500i fältet och skicka.
Servern svarar med sidan tillbaka, och i listan står:
Antalet biljetter är 1 till 10.
Ingenting togs emot. DataAnnotationsValidator körde attributen
på servern, efter att formuläret kommit in – och den bryr sig inte om vad
webbläsaren tyckte.
Det som händer i webbläsaren gör att användaren slipper vänta på ett svar för att få veta att fältet är tomt. Det är bekvämlighet, inte ett skydd. Den som bara har den första har ingen validering alls.
Gör sedan samma test på ditt eget formulär, på ett fält med
[Range] eller [StringLength]. Skriv i
README.md vilket fält du testade, vad du ändrade och vad servern
svarade – det är ett C-krav.
5. Vad som fångas, och vad som inte gör det
Prova a@b i e-postfältet. Det går igenom. [EmailAddress]
kontrollerar formen – att det finns ett @ med något på båda sidor –
inte att adressen finns.
Det är värt att säga rakt ut vad valideringsattribut är till för:
| Fångar | Fångar inte |
|---|---|
| Ett tomt fält | En påhittad adress som ser rätt ut |
| 500 där det ska stå 1–10 | Ett värde som är tillåtet men fel |
| En text som är för lång | Någon som medvetet försöker |
| Slarv och misstag | Angrepp |
Och kedjan har, som du såg på lektion 32, exakt ett ställe som håller.
Databasen fångar inte betyget 99 – [Range] blev ingenting i tabellen.
Webbläsaren fångar det bara tills någon trycker F12. Det som återstår är
DataAnnotationsValidator plus OnValidSubmit, på
servern.
Den som medvetet försöker är område 7.