Kurs:Täglich Controllers Übungen und Kurs:Täglich Model Binding Übungen: Unterschied zwischen den Seiten
(Unterschied zwischen Seiten)
Die Seite wurde neu angelegt: „= ASP.NET Core MVC: Controller & Action Methods – Code-Spickzettel = == 1. Einfacher Controller mit Action Methods == <syntaxhighlight lang="csharp"> // HomeController.cs namespace MyApp.Controllers { [Controller] public class HomeController : Controller { [Route("home")] [Route("/")] public string Index() { return "Hello from Index"; } [Route("about")] public string About…“ |
Die Seite wurde neu angelegt: „= Model Binding & Validation – ASP.NET Core MVC (Spickzettel) = == Standard-Model-Binding (Query, Route, Form) == <syntaxhighlight lang="csharp"> // Route mit optionalen Parametern (aus Query oder Route gebunden) [Route("buchladen/{buchid?}/{eingeloggt?}")] public IActionResult Index(int? buchid, bool? eingeloggt) { return Content($"Buch-ID: {buchid}, Eingeloggt: {eingeloggt}", "text/plain"); } // Route mit festem (required) Parameter (aus Route…“ |
||
| Zeile 1: | Zeile 1: | ||
= ASP.NET Core MVC | = Model Binding & Validation – ASP.NET Core MVC (Spickzettel) = | ||
== Standard-Model-Binding (Query, Route, Form) == | |||
<syntaxhighlight lang="csharp"> | <syntaxhighlight lang="csharp"> | ||
// | // Route mit optionalen Parametern (aus Query oder Route gebunden) | ||
[Route("buchladen/{buchid?}/{eingeloggt?}")] | |||
public IActionResult Index(int? buchid, bool? eingeloggt) | |||
{ | |||
return Content($"Buch-ID: {buchid}, Eingeloggt: {eingeloggt}", "text/plain"); | |||
} | |||
// Route mit festem (required) Parameter (aus Route gebunden) | |||
[Route("shop/buecher/{id}")] | |||
public IActionResult Buch() | |||
{ | { | ||
[ | int id = Convert.ToInt32(Request.RouteValues["id"]); | ||
return Content($"<h1>Buch-Shop {id}</h1>", "text/html"); | |||
} | |||
</syntaxhighlight> | |||
== [FromQuery] und [FromRoute] verwenden == | |||
<syntaxhighlight lang="csharp"> | |||
[Route("buchladen/{buchid?}/{eingeloggt?}")] | |||
public IActionResult Index([FromQuery] int? buchid, [FromRoute] bool? eingeloggt) | |||
{ | |||
// Explizites Binding: buchid nur aus Query, eingeloggt nur aus Route | |||
return Content($"Buch-ID: {buchid}, Eingeloggt: {eingeloggt}"); | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == Model Binding mit Modelklassen == | ||
<syntaxhighlight lang="csharp"> | <syntaxhighlight lang="csharp"> | ||
// Modelklasse | |||
public | public class Buch | ||
{ | { | ||
public int? BuchId { get; set; } | |||
public string? Autor { get; set; } | |||
public override string ToString() => $"Buch: {BuchId}, Autor: {Autor}"; | |||
} | } | ||
[Route(" | // Controller | ||
public | [Route("buchladen/{buchid?}/{eingeloggt?}")] | ||
public IActionResult Index([FromQuery] int? buchid, [FromRoute] bool? eingeloggt, Buch buch) | |||
{ | { | ||
return Content(" | return Content($"Buch-ID: {buchid}, Buch: {buch}", "text/plain"); | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == Model Validation mit DataAnnotations == | ||
<syntaxhighlight lang="csharp"> | <syntaxhighlight lang="csharp"> | ||
using System.ComponentModel.DataAnnotations; | |||
public | |||
public class Person | |||
{ | { | ||
[Required(ErrorMessage = "{0} darf nicht leer sein")] | |||
return | public string? Name { get; set; } | ||
[EmailAddress] | |||
public string? Email { get; set; } | |||
[Compare("Passwort", ErrorMessage = "Passwörter stimmen nicht überein")] | |||
public string? PasswortBestätigung { get; set; } | |||
} | |||
// Controller | |||
public IActionResult Erstellen(Person person) | |||
{ | |||
if (!ModelState.IsValid) | |||
return View(person); | |||
// Speicherung etc. | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == Custom Validation Attribute Beispiel == | ||
<syntaxhighlight lang="csharp"> | <syntaxhighlight lang="csharp"> | ||
// | // Validator: ToDate >= FromDate | ||
public class DatumsbereichValidatorAttribute : ValidationAttribute | |||
public | |||
{ | { | ||
return | public string VonProperty { get; } | ||
public DatumsbereichValidatorAttribute(string vonProperty) => VonProperty = vonProperty; | |||
protected override ValidationResult? IsValid(object? value, ValidationContext context) | |||
{ | |||
if (value is DateTime toDate) | |||
{ | |||
var fromProp = context.ObjectType.GetProperty(VonProperty); | |||
if (fromProp?.GetValue(context.ObjectInstance) is DateTime fromDate && fromDate > toDate) | |||
return new ValidationResult(ErrorMessage, new[] { VonProperty, context.MemberName! }); | |||
} | |||
return ValidationResult.Success; | |||
} | |||
} | } | ||
</syntaxhighlight> | |||
== Model-Level Validation mit IValidatableObject == | |||
public | <syntaxhighlight lang="csharp"> | ||
public class Person : IValidatableObject | |||
{ | { | ||
return | public DateTime? Geburtsdatum { get; set; } | ||
public int? Alter { get; set; } | |||
public IEnumerable<ValidationResult> Validate(ValidationContext context) | |||
{ | |||
if (!Geburtsdatum.HasValue && !Alter.HasValue) | |||
yield return new ValidationResult("Geburtsdatum ODER Alter muss angegeben werden", new[] { nameof(Alter) }); | |||
} | |||
} | } | ||
</syntaxhighlight> | |||
== [Bind] und [BindNever] Attribute == | |||
// | <syntaxhighlight lang="csharp"> | ||
[ | // Nur bestimmte Felder binden | ||
public | [HttpPost] | ||
public IActionResult Erstellen([Bind("Titel", "Beschreibung")] Produkt produkt) { ... } | |||
// Niemals aus Request binden | |||
public class Produkt | |||
{ | { | ||
[BindNever] | |||
public DateTime ErstelltAm { get; set; } | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == [FromBody]: JSON/XML Body-Parameter binden == | ||
<syntaxhighlight lang="csharp"> | <syntaxhighlight lang="csharp"> | ||
[Route(" | [Route("registrieren")] | ||
public IActionResult | public IActionResult Index([FromBody] Person person) | ||
{ | { | ||
if ( | if (!ModelState.IsValid) { ... } | ||
return Content($"{person}"); | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == Collection Binding (Listen/Arrays binden) == | ||
<syntaxhighlight lang="csharp"> | <syntaxhighlight lang="csharp"> | ||
public class Person | |||
{ | |||
public List<string?> Interessen { get; set; } = new(); | |||
} | |||
// | // JSON: { "Name": "Anna", "Interessen": ["Musik", "Lesen", "Coding"] } | ||
return | public IActionResult Index(Person person) | ||
{ | |||
return Content($"Person: {person.Name}, Interessen: {string.Join(",", person.Interessen)}"); | |||
} | |||
</syntaxhighlight> | |||
== [FromHeader]: Parameter aus HTTP-Header == | |||
<syntaxhighlight lang="csharp"> | |||
return | [Route("registrieren")] | ||
public IActionResult Index(Person person, [FromHeader(Name = "User-Agent")] string userAgent) | |||
{ | |||
return Content($"{person}, {userAgent}"); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == Input Formatters registrieren (z.B. XML) == | ||
<syntaxhighlight lang="csharp"> | <syntaxhighlight lang="csharp"> | ||
var builder = WebApplication.CreateBuilder(args); | |||
builder.Services.AddControllers().AddXmlSerializerFormatters(); | |||
</syntaxhighlight> | |||
== Custom Model Binder registrieren == | |||
// | <syntaxhighlight lang="csharp"> | ||
// Custom Binder implementieren | |||
public class PersonModelBinder : IModelBinder { ... } | |||
// | // BinderProvider registrieren (Startup/Program.cs) | ||
builder.Services.AddControllers(options => { | |||
options.ModelBinderProviders.Insert(0, new PersonBinderProvider()); | |||
}); | |||
</syntaxhighlight> | |||
---- | |||
= | = Übungen / Mini-Aufgaben = | ||
* Schreibe eine Controller-Methode, die einen Parameter aus der Query und einen aus der Route bindet. | |||
* Controller | * Erstelle ein Model mit mindestens drei Properties und validiere sie mit DataAnnotations. | ||
* | * Schreibe ein Custom ValidationAttribute, das prüft, ob ein Datum in der Zukunft liegt. | ||
* | * Nutze [FromBody], um ein komplettes Model aus JSON im Request-Body zu binden. | ||
* | * Verwende [BindNever], um eine Eigenschaft vor Overposting zu schützen. | ||
* | * Binde eine Liste von Strings im Model und fülle sie über ein Array im Request. | ||
* Hole den User-Agent per [FromHeader] und gib ihn in der Response aus. | |||
Aktuelle Version vom 24. Juni 2025, 04:23 Uhr
Model Binding & Validation – ASP.NET Core MVC (Spickzettel)
Standard-Model-Binding (Query, Route, Form)
// Route mit optionalen Parametern (aus Query oder Route gebunden)
[Route("buchladen/{buchid?}/{eingeloggt?}")]
public IActionResult Index(int? buchid, bool? eingeloggt)
{
return Content($"Buch-ID: {buchid}, Eingeloggt: {eingeloggt}", "text/plain");
}
// Route mit festem (required) Parameter (aus Route gebunden)
[Route("shop/buecher/{id}")]
public IActionResult Buch()
{
int id = Convert.ToInt32(Request.RouteValues["id"]);
return Content($"<h1>Buch-Shop {id}</h1>", "text/html");
}
[FromQuery] und [FromRoute] verwenden
[Route("buchladen/{buchid?}/{eingeloggt?}")]
public IActionResult Index([FromQuery] int? buchid, [FromRoute] bool? eingeloggt)
{
// Explizites Binding: buchid nur aus Query, eingeloggt nur aus Route
return Content($"Buch-ID: {buchid}, Eingeloggt: {eingeloggt}");
}
Model Binding mit Modelklassen
// Modelklasse
public class Buch
{
public int? BuchId { get; set; }
public string? Autor { get; set; }
public override string ToString() => $"Buch: {BuchId}, Autor: {Autor}";
}
// Controller
[Route("buchladen/{buchid?}/{eingeloggt?}")]
public IActionResult Index([FromQuery] int? buchid, [FromRoute] bool? eingeloggt, Buch buch)
{
return Content($"Buch-ID: {buchid}, Buch: {buch}", "text/plain");
}
Model Validation mit DataAnnotations
using System.ComponentModel.DataAnnotations;
public class Person
{
[Required(ErrorMessage = "{0} darf nicht leer sein")]
public string? Name { get; set; }
[EmailAddress]
public string? Email { get; set; }
[Compare("Passwort", ErrorMessage = "Passwörter stimmen nicht überein")]
public string? PasswortBestätigung { get; set; }
}
// Controller
public IActionResult Erstellen(Person person)
{
if (!ModelState.IsValid)
return View(person);
// Speicherung etc.
}
Custom Validation Attribute Beispiel
// Validator: ToDate >= FromDate
public class DatumsbereichValidatorAttribute : ValidationAttribute
{
public string VonProperty { get; }
public DatumsbereichValidatorAttribute(string vonProperty) => VonProperty = vonProperty;
protected override ValidationResult? IsValid(object? value, ValidationContext context)
{
if (value is DateTime toDate)
{
var fromProp = context.ObjectType.GetProperty(VonProperty);
if (fromProp?.GetValue(context.ObjectInstance) is DateTime fromDate && fromDate > toDate)
return new ValidationResult(ErrorMessage, new[] { VonProperty, context.MemberName! });
}
return ValidationResult.Success;
}
}
Model-Level Validation mit IValidatableObject
public class Person : IValidatableObject
{
public DateTime? Geburtsdatum { get; set; }
public int? Alter { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext context)
{
if (!Geburtsdatum.HasValue && !Alter.HasValue)
yield return new ValidationResult("Geburtsdatum ODER Alter muss angegeben werden", new[] { nameof(Alter) });
}
}
[Bind] und [BindNever] Attribute
// Nur bestimmte Felder binden
[HttpPost]
public IActionResult Erstellen([Bind("Titel", "Beschreibung")] Produkt produkt) { ... }
// Niemals aus Request binden
public class Produkt
{
[BindNever]
public DateTime ErstelltAm { get; set; }
}
[FromBody]: JSON/XML Body-Parameter binden
[Route("registrieren")]
public IActionResult Index([FromBody] Person person)
{
if (!ModelState.IsValid) { ... }
return Content($"{person}");
}
Collection Binding (Listen/Arrays binden)
public class Person
{
public List<string?> Interessen { get; set; } = new();
}
// JSON: { "Name": "Anna", "Interessen": ["Musik", "Lesen", "Coding"] }
public IActionResult Index(Person person)
{
return Content($"Person: {person.Name}, Interessen: {string.Join(",", person.Interessen)}");
}
[FromHeader]: Parameter aus HTTP-Header
[Route("registrieren")]
public IActionResult Index(Person person, [FromHeader(Name = "User-Agent")] string userAgent)
{
return Content($"{person}, {userAgent}");
}
Input Formatters registrieren (z.B. XML)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers().AddXmlSerializerFormatters();
Custom Model Binder registrieren
// Custom Binder implementieren
public class PersonModelBinder : IModelBinder { ... }
// BinderProvider registrieren (Startup/Program.cs)
builder.Services.AddControllers(options => {
options.ModelBinderProviders.Insert(0, new PersonBinderProvider());
});
Übungen / Mini-Aufgaben
- Schreibe eine Controller-Methode, die einen Parameter aus der Query und einen aus der Route bindet.
- Erstelle ein Model mit mindestens drei Properties und validiere sie mit DataAnnotations.
- Schreibe ein Custom ValidationAttribute, das prüft, ob ein Datum in der Zukunft liegt.
- Nutze [FromBody], um ein komplettes Model aus JSON im Request-Body zu binden.
- Verwende [BindNever], um eine Eigenschaft vor Overposting zu schützen.
- Binde eine Liste von Strings im Model und fülle sie über ein Array im Request.
- Hole den User-Agent per [FromHeader] und gib ihn in der Response aus.