EditForm, Input-komponenterna och DataAnnotations. Vi bygger formulär som validerar både i UI och i C#-modellen.
Ett formulär byggs runt en EditForm som är kopplad till en C#-modell. Inuti formuläret används specialiserade Input*-komponenter som vet hur de ska binda mot egenskaper.
@page "/register"
<EditForm Model="model" OnValidSubmit="HandleSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label>Förnamn</label>
<InputText @bind-Value="model.FirstName" />
<ValidationMessage For="@(() => model.FirstName)" />
</div>
<div>
<label>E-post</label>
<InputText @bind-Value="model.Email" />
<ValidationMessage For="@(() => model.Email)" />
</div>
<button type="submit">Registrera</button>
</EditForm>
@code {
private RegisterModel model = new();
private void HandleSubmit()
{
Console.WriteLine($"Registrerar {model.FirstName} ({model.Email})");
}
}
using System.ComponentModel.DataAnnotations;
public class RegisterModel
{
[Required(ErrorMessage = "Förnamn krävs")]
[StringLength(50, MinimumLength = 2)]
public string FirstName { get; set; } = "";
[Required, EmailAddress(ErrorMessage = "Ogiltig e-post")]
public string Email { get; set; } = "";
[Required, MinLength(8, ErrorMessage = "Lösenord måste vara minst 8 tecken")]
public string Password { get; set; } = "";
[Range(18, 120, ErrorMessage = "Ålder måste vara mellan 18 och 120")]
public int Age { get; set; }
[Compare(nameof(Password), ErrorMessage = "Lösenorden matchar inte")]
public string PasswordConfirm { get; set; } = "";
}
| Komponent | HTML-element | För typ |
|---|---|---|
InputText | <input type="text"> | string |
InputTextArea | <textarea> | string |
InputNumber | <input type="number"> | int, decimal, double |
InputDate | <input type="date"> | DateTime, DateOnly |
InputCheckbox | <input type="checkbox"> | bool |
InputSelect | <select> | enum, string |
InputRadioGroup + InputRadio | <input type="radio"> | enum, string |
InputFile | <input type="file"> | Filuppladdning |
public enum Roll { Anvandare, Redaktor, Admin }
public class UserModel
{
[Required] public Roll Roll { get; set; }
}
<InputSelect @bind-Value="model.Roll">
@foreach (var r in Enum.GetValues<Roll>())
{
<option value="@r">@r</option>
}
</InputSelect>
<InputRadioGroup @bind-Value="model.Roll">
@foreach (var r in Enum.GetValues<Roll>())
{
<label>
<InputRadio Value="r" /> @r
</label>
}
</InputRadioGroup>
| Händelse | När den körs |
|---|---|
OnValidSubmit | Vid submit om alla valideringar är OK |
OnInvalidSubmit | Vid submit om det finns valideringsfel |
OnSubmit | Vid submit oavsett validering (manuell hantering) |
OnSubmit ELLER OnValidSubmit/OnInvalidSubmit
Inte både och. Om du behöver custom valideringslogik vid submit, använd OnSubmit + EditContext.Validate().
public class BookingModel : IValidatableObject
{
[Required] public DateTime CheckIn { get; set; }
[Required] public DateTime CheckOut { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext ctx)
{
if (CheckOut <= CheckIn)
{
yield return new ValidationResult(
"Utcheckning måste vara efter incheckning",
new[] { nameof(CheckOut) });
}
}
}
I .NET 10 finns en ny, kraftfullare valideringsmotor som klarar nested objects och collections direkt — utan att du behöver skriva egen IValidatableObject. Aktivera den i Program.cs:
// Program.cs
builder.Services.AddValidation();
Märk rotklassen med [ValidatableType]:
// Models/Order.cs (MÅSTE ligga i en .cs-fil — inte i .razor!)
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Components.Forms;
[ValidatableType]
public class Order
{
[Required] public string Customer { get; set; } = "";
[MinLength(1, ErrorMessage = "Minst en orderrad krävs")]
public List<OrderItem> Items { get; set; } = new();
}
public class OrderItem
{
[Required] public string ProductName { get; set; } = "";
[Range(1, 100)] public int Quantity { get; set; }
}
Nu valideras varje OrderItem i listan automatiskt när formuläret submitas — det går inte med klassiska DataAnnotationsValidator ensamt.
AddValidation() + [ValidatableType] ger validering av nested objects och collections..cs-filer (källgeneratorn kan inte se klasser deklarerade inuti .razor).<InputHidden> för dolda fält med two-way binding.AddValidation() kan också användas för Minimal APIs i .NET 10.DataAnnotationsValidator (fungerar fortfarande och är enklast att förstå). När du senare behover validera komplexa modeller med listor — använd AddValidation().
<InputFile OnChange="HandleSelected" multiple accept=".jpg,.png" />
@if (preview != null)
{
<img src="@preview" style="max-width:200px" />
}
@code {
private string? preview;
private async Task HandleSelected(InputFileChangeEventArgs e)
{
var file = e.File;
using var stream = file.OpenReadStream(maxAllowedSize: 5 * 1024 * 1024);
using var ms = new MemoryStream();
await stream.CopyToAsync(ms);
var base64 = Convert.ToBase64String(ms.ToArray());
preview = $"data:{file.ContentType};base64,{base64}";
}
}
maxAllowedSize explicit. Validera även MIME-typ och filändelse på servern, inte bara i UI:t.
Lös övningarna självständigt. Det finns inget facit — lärandet sker i processen.
IValidatableObject för att säkerställa att utcheckning är efter incheckning och att vistelsen är max 14 dagar.
List<Address>. Validera att minst en adress finns.