DatumBereich
Das DatumBereichAttribute validiert ein DateTime-Feld gegen einen
Datumsbereich. Das DateTime-EditorTemplate liest den Bereich aus dem Attribut und
setzt Min/Max am <input type="date">. Jedes Beispiel zeigt in Tabs die
cshtml, das ViewModel und den Controller (GET/POST);
darunter das funktionierende Formular. Ein Datum ausserhalb des Bereichs löst die Validierung aus.
Feste Daten (string, string)
Fester Bereich 01.01.2020 – 31.12.2030 über zwei Datums-Strings.
@model DatumBereichFestBeispielViewModel
<form asp-area="Basis" asp-controller="DatumBereich" asp-action="Fest" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
@Html.EditorFor(m => m.Datum)
@Html.Fmh(Fmh.Button()
.Text("Absenden")
.Size(ButtonSize.Sm)
.Attributes(new { @class = "mt-2" }))
</form>
using System;
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation;
namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
public class DatumBereichFestBeispielViewModel
{
[Display(Name = "Datum (01.01.2020 – 31.12.2030)")]
[DatumBereich("01.01.2020", "31.12.2030")]
public DateTime? Datum { get; set; }
}
}
using FMH.Komponente.Basis.Erweiterungen;
using FMH.Komponente.Basis.Ui.Feedback.Alert;
using FMH.Komponente.WebUI.Areas.Basis.Models;
using Microsoft.AspNetCore.Mvc;
namespace FMH.Komponente.WebUI.Areas.Basis.Controllers.Beispiele
{
// Ein Controller pro Attribut (DatumBereich); je eine Action/View pro Bereichs-Variante.
// Die POST-Actions illustrieren die Validierungslogik: liegt das Datum im erlaubten Bereich,
// ist ModelState.IsValid true.
[Area("Basis")]
public class DatumBereichController : Controller
{
[HttpGet]
public IActionResult Fest()
{
return this.View(new DatumBereichFestBeispielViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Fest(DatumBereichFestBeispielViewModel modell)
{
if (this.ModelState.IsValid)
{
// Gültig: das Datum liegt im per [DatumBereich] erlaubten Bereich.
// PRG-Pattern (Post-Redirect-Get): nach Erfolg per Redirect auf die GET-Action,
// damit ein erneutes Laden das Formular nicht nochmals abschickt.
this.AddAlert("Formular ist gültig – Validierung erfolgreich.", AlertType.Success, autoHide: true);
return this.RedirectToAction(nameof(this.Fest));
}
// Ungültig: Datum ausserhalb des Bereichs -> dieselbe View mit den Validierungsfehlern.
return this.View(modell);
}
[HttpGet]
public IActionResult Offset()
{
return this.View(new DatumBereichOffsetBeispielViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Offset(DatumBereichOffsetBeispielViewModel modell)
{
if (this.ModelState.IsValid)
{
this.AddAlert("Formular ist gültig – Validierung erfolgreich.", AlertType.Success, autoHide: true);
return this.RedirectToAction(nameof(this.Offset));
}
return this.View(modell);
}
[HttpGet]
public IActionResult Tage()
{
return this.View(new DatumBereichTageBeispielViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Tage(DatumBereichTageBeispielViewModel modell)
{
if (this.ModelState.IsValid)
{
this.AddAlert("Formular ist gültig – Validierung erfolgreich.", AlertType.Success, autoHide: true);
return this.RedirectToAction(nameof(this.Tage));
}
return this.View(modell);
}
}
}
Darstellung
Das DatumBereichAttribute validiert ein DateTime-Feld gegen einen Bereich. Mit zwei Datums-Strings (Format dd.MM.yyyy, de-CH) werden feste Grenzen gesetzt. Das DateTime-EditorTemplate liest den Bereich aus dem Attribut und begrenzt den <input type="date"> entsprechend; server- und clientseitig (unobtrusive) wird geprüft.
[Display(Name = "Datum")]
[DatumBereich("01.01.2020", "31.12.2030")]
public DateTime? Datum { get; set; }
Ein leeres Feld ist gültig (das Attribut prüft nur bei vorhandenem Wert); für ein Pflichtfeld zusätzlich [Required] setzen.
Konstruktoren (Bereich)
| Überladung | Bereich |
|---|---|
[DatumBereich] |
01.01.1970 bis 31.12. (heute + 10 Jahre) |
[DatumBereich("01.01.2020", "31.12.2030")] |
feste Daten, Format dd.MM.yyyy (de-CH) |
[DatumBereich("01.01.2000", 5)] |
Minimum fest, Maximum = heute + 5 Jahre (siehe «Jahr-Offset») |
[DatumBereich(-30, 30)] |
relativ zu heute in Tagen (siehe «Relative Tage») |
Fehlermeldung
Ohne eigene ErrorMessage erscheint die lokalisierte Standardmeldung _FmhWebMvc.ValidationDateTimeRange mit eingesetztem Min-/Max-Datum. Für eine eigene Ressourcen-Meldung ErrorMessageResourceType/-Name setzen; die Platzhalter für die Grenzen sind dort {{0}} (Min) und {{1}} (Max), da die Meldung zweistufig formatiert wird.
Jahr-Offset (string, int)
Minimum fest, Maximum = heute + 5 Jahre.
@model DatumBereichOffsetBeispielViewModel
<form asp-area="Basis" asp-controller="DatumBereich" asp-action="Offset" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
@Html.EditorFor(m => m.Datum)
@Html.Fmh(Fmh.Button()
.Text("Absenden")
.Size(ButtonSize.Sm)
.Attributes(new { @class = "mt-2" }))
</form>
using System;
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation;
namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
public class DatumBereichOffsetBeispielViewModel
{
[Display(Name = "Datum (01.01.2000 bis heute + 5 Jahre)")]
[DatumBereich("01.01.2000", 5)]
public DateTime? Datum { get; set; }
}
}
using FMH.Komponente.Basis.Erweiterungen;
using FMH.Komponente.Basis.Ui.Feedback.Alert;
using FMH.Komponente.WebUI.Areas.Basis.Models;
using Microsoft.AspNetCore.Mvc;
namespace FMH.Komponente.WebUI.Areas.Basis.Controllers.Beispiele
{
// Ein Controller pro Attribut (DatumBereich); je eine Action/View pro Bereichs-Variante.
// Die POST-Actions illustrieren die Validierungslogik: liegt das Datum im erlaubten Bereich,
// ist ModelState.IsValid true.
[Area("Basis")]
public class DatumBereichController : Controller
{
[HttpGet]
public IActionResult Fest()
{
return this.View(new DatumBereichFestBeispielViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Fest(DatumBereichFestBeispielViewModel modell)
{
if (this.ModelState.IsValid)
{
// Gültig: das Datum liegt im per [DatumBereich] erlaubten Bereich.
// PRG-Pattern (Post-Redirect-Get): nach Erfolg per Redirect auf die GET-Action,
// damit ein erneutes Laden das Formular nicht nochmals abschickt.
this.AddAlert("Formular ist gültig – Validierung erfolgreich.", AlertType.Success, autoHide: true);
return this.RedirectToAction(nameof(this.Fest));
}
// Ungültig: Datum ausserhalb des Bereichs -> dieselbe View mit den Validierungsfehlern.
return this.View(modell);
}
[HttpGet]
public IActionResult Offset()
{
return this.View(new DatumBereichOffsetBeispielViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Offset(DatumBereichOffsetBeispielViewModel modell)
{
if (this.ModelState.IsValid)
{
this.AddAlert("Formular ist gültig – Validierung erfolgreich.", AlertType.Success, autoHide: true);
return this.RedirectToAction(nameof(this.Offset));
}
return this.View(modell);
}
[HttpGet]
public IActionResult Tage()
{
return this.View(new DatumBereichTageBeispielViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Tage(DatumBereichTageBeispielViewModel modell)
{
if (this.ModelState.IsValid)
{
this.AddAlert("Formular ist gültig – Validierung erfolgreich.", AlertType.Success, autoHide: true);
return this.RedirectToAction(nameof(this.Tage));
}
return this.View(modell);
}
}
}
Darstellung
Mit [DatumBereich(string minDatum, int maxJahrOffset)] ist das Minimum fest und das Maximum das heutige Datum plus die angegebenen Jahre (Uhrzeit 23:59:59). Bei negativem Offset wird ein Tag addiert (Schaltjahr-Behandlung 29. Februar).
[Display(Name = "Datum")]
[DatumBereich("01.01.2000", 5)]
public DateTime? Datum { get; set; }
Relative Tage (int, int)
Beide Grenzen relativ zu heute: -30 bis +30 Tage.
@model DatumBereichTageBeispielViewModel
<form asp-area="Basis" asp-controller="DatumBereich" asp-action="Tage" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
@Html.EditorFor(m => m.Datum)
@Html.Fmh(Fmh.Button()
.Text("Absenden")
.Size(ButtonSize.Sm)
.Attributes(new { @class = "mt-2" }))
</form>
using System;
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation;
namespace FMH.Komponente.WebUI.Areas.Basis.Models
{
public class DatumBereichTageBeispielViewModel
{
[Display(Name = "Datum (heute -30 bis +30 Tage)")]
[DatumBereich(-30, 30)]
public DateTime? Datum { get; set; }
}
}
using FMH.Komponente.Basis.Erweiterungen;
using FMH.Komponente.Basis.Ui.Feedback.Alert;
using FMH.Komponente.WebUI.Areas.Basis.Models;
using Microsoft.AspNetCore.Mvc;
namespace FMH.Komponente.WebUI.Areas.Basis.Controllers.Beispiele
{
// Ein Controller pro Attribut (DatumBereich); je eine Action/View pro Bereichs-Variante.
// Die POST-Actions illustrieren die Validierungslogik: liegt das Datum im erlaubten Bereich,
// ist ModelState.IsValid true.
[Area("Basis")]
public class DatumBereichController : Controller
{
[HttpGet]
public IActionResult Fest()
{
return this.View(new DatumBereichFestBeispielViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Fest(DatumBereichFestBeispielViewModel modell)
{
if (this.ModelState.IsValid)
{
// Gültig: das Datum liegt im per [DatumBereich] erlaubten Bereich.
// PRG-Pattern (Post-Redirect-Get): nach Erfolg per Redirect auf die GET-Action,
// damit ein erneutes Laden das Formular nicht nochmals abschickt.
this.AddAlert("Formular ist gültig – Validierung erfolgreich.", AlertType.Success, autoHide: true);
return this.RedirectToAction(nameof(this.Fest));
}
// Ungültig: Datum ausserhalb des Bereichs -> dieselbe View mit den Validierungsfehlern.
return this.View(modell);
}
[HttpGet]
public IActionResult Offset()
{
return this.View(new DatumBereichOffsetBeispielViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Offset(DatumBereichOffsetBeispielViewModel modell)
{
if (this.ModelState.IsValid)
{
this.AddAlert("Formular ist gültig – Validierung erfolgreich.", AlertType.Success, autoHide: true);
return this.RedirectToAction(nameof(this.Offset));
}
return this.View(modell);
}
[HttpGet]
public IActionResult Tage()
{
return this.View(new DatumBereichTageBeispielViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Tage(DatumBereichTageBeispielViewModel modell)
{
if (this.ModelState.IsValid)
{
this.AddAlert("Formular ist gültig – Validierung erfolgreich.", AlertType.Success, autoHide: true);
return this.RedirectToAction(nameof(this.Tage));
}
return this.View(modell);
}
}
}
Darstellung
Mit [DatumBereich(int minTageVomAktuellenDatum, int maxDatumTage)] sind beide Grenzen relativ zum heutigen Datum in Tagen; negative Werte für die Vergangenheit sind möglich.
[Display(Name = "Datum")]
[DatumBereich(-30, 30)]
public DateTime? Datum { get; set; }
Hinweis: Die relativen Grenzen werden bei der Instanzierung des Attributs mit DateTime.Now berechnet. Da der Validator Attribut-Instanzen cached, wandert der Bereich in einer lang laufenden Anwendung nicht pro Request mit.