DocumentUploadRequired
Pflicht-Upload
Ohne mindestens ein zugeordnetes Dokument ist das Formular ungültig. Geprüft wird DokumentIds des DokumentListeViewModel.
@model DokumentListePflichtBeispielViewModel
@* Die Prüfung von DocumentUploadRequired läuft serverseitig, die Meldung erscheint also erst
nach dem Absenden – beim Feld, wie jede andere Meldung auch. *@
<form asp-area="FileUploadValidierung" asp-controller="DokumentListePflichtBeispiel" asp-action="Index" method="post">
@Html.EditorFor(m => m.Nachweise)
@Html.Fmh(Fmh.Button()
.Text("Absenden")
.Size(ButtonSize.Sm)
.Attributes(new { @class = "mt-3" }))
</form>
using System.ComponentModel.DataAnnotations;
using FMH.Komponente.Basis.Ui.Validation.DataAnnotation;
using FMH.Komponente.FileUpload.Models;
using FMH.Komponente.FileUpload.Ui.Validation.DataAnnotation;
using FMH.Komponente.Infrastruktur;
namespace FMH.Komponente.WebUI.Areas.FileUploadValidierung.Models
{
public class DokumentListePflichtBeispielViewModel
{
/// <summary>
/// DocumentUploadRequired sucht am ViewModel die erste Eigenschaft vom Typ
/// DokumentListeViewModel und prüft deren DokumentIds. Die Liste startet in diesem Beispiel
/// bewusst leer: Sind bereits Dokumente vorhanden, gilt die Bedingung als erfüllt und die
/// Meldung wäre nie zu sehen.
/// </summary>
[UIHint(UiEditor.FileUpload.DokumentListe)]
[Display(Name = "Nachweis (mindestens ein Dokument)")]
[DocumentUploadRequired]
[AdditionalMetadata(UiMetadata.FileUpload.UploadUrl, "/FileUploadValidierung/DokumentListePflichtBeispiel/Upload")]
[AdditionalMetadata(UiMetadata.FileUpload.MaxFileSizeInMb, "1")]
[AdditionalMetadata(UiMetadata.FileUpload.MaxFiles, "1")]
[AdditionalMetadata(UiMetadata.FileUpload.DownloadActionName, "Download")]
[AdditionalMetadata(UiMetadata.FileUpload.DownloadControllerName, "DokumentListePflichtBeispiel")]
public DokumentListeViewModel Nachweise { get; set; } = new DokumentListeViewModel();
}
}
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading;
using FMH.Komponente.Basis.Erweiterungen;
using FMH.Komponente.Basis.Ui.Feedback.Alert;
using FMH.Komponente.WebUI.Areas.FileUploadValidierung.Models;
using Microsoft.AspNetCore.Mvc;
namespace FMH.Komponente.WebUI.Areas.FileUploadValidierung.Controllers.Beispiele
{
/// <summary>
/// Zeigt [DocumentUploadRequired]. Die angezeigte Dokumentliste bleibt hier bewusst immer leer:
/// Sobald bereits Dokumente zugeordnet sind, gilt die Bedingung über das versteckte Feld
/// «NachweiseExistingDocuments» als erfüllt, die Pflichtmeldung wäre dann nicht mehr auslösbar
/// und das Beispiel nur einmal vorführbar.
/// </summary>
[Area("FileUploadValidierung")]
public class DokumentListePflichtBeispielController : Controller
{
/// <summary>
/// Nur die Zuordnung Id -> Name für die Rückmeldung; die Einträge landen nicht in der Tabelle.
/// </summary>
private static readonly ConcurrentDictionary<int, string> Dokumente =
new ConcurrentDictionary<int, string>();
private static int letzteId;
[HttpGet]
public IActionResult Index()
{
return this.View(new DokumentListePflichtBeispielViewModel());
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index(DokumentListePflichtBeispielViewModel modell)
{
// Der ungültige Zweig ist hier der Lerninhalt: Ohne übertragenes Dokument ist
// DokumentIds leer, DocumentUploadRequired meldet Document_Required und die View wird
// mit dem Fehler erneut angezeigt. Die Prüfung läuft rein serverseitig, es gibt keinen
// unaufdringlichen Client-Adapter dafür.
if (this.ModelState.IsValid == false)
{
return this.View(modell);
}
var namen = modell.Nachweise.DokumentIds
.Select(id => Dokumente.TryGetValue(id, out var name) ? name : $"Id {id}");
this.AddAlert(
$"Formular gültig – Nachweis vorhanden: {string.Join(", ", namen)}",
AlertType.Success,
autoHide: true);
return this.RedirectToAction(nameof(this.Index));
}
/// <summary>
/// Der Upload-Endpunkt dieses Beispiels. Antwort muss ein Json mit der Eigenschaft
/// <c>id</c> sein, erst diese Id landet als verstecktes Feld <c>DokumentIds</c> im
/// Formular und macht die Pflichtprüfung zufrieden.
/// </summary>
/// <returns>Json mit der vergebenen Id.</returns>
[HttpPost]
public IActionResult Upload()
{
if (this.Request.Headers.ContainsKey("IsDropzoneRequest") == false || this.Request.Form.Files.Count == 0)
{
return this.Json(new { id = 0 });
}
var datei = this.Request.Form.Files[0];
var bezeichnung = this.Request.Form["DateiBezeichnung"].ToString();
var name = string.IsNullOrWhiteSpace(bezeichnung) ? datei.FileName : bezeichnung;
var id = Interlocked.Increment(ref letzteId);
Dokumente[id] = name;
return this.Json(new { id });
}
/// <summary>
/// Der Download-Endpunkt. In diesem Beispiel bleibt die Tabelle leer, der Endpunkt ist
/// dennoch konfiguriert, damit das ViewModel vollständig ist.
/// </summary>
/// <param name="id">Die Id des Dokuments.</param>
/// <returns>Die Datei zum Herunterladen.</returns>
[HttpGet]
public IActionResult Download(int id)
{
if (Dokumente.TryGetValue(id, out var name) == false)
{
return this.NotFound();
}
var inhalt = Encoding.UTF8.GetBytes($"Platzhalter-Inhalt für «{name}» (Id {id}).");
return this.File(inhalt, "text/plain", name);
}
}
}
Darstellung
[DocumentUploadRequired] macht mindestens ein Dokument zur Pflicht.
[UIHint(UiEditor.FileUpload.DokumentListe)]
[Display(Name = "Nachweis (mindestens ein Dokument)")]
[DocumentUploadRequired]
[AdditionalMetadata(UiMetadata.FileUpload.UploadUrl, "/FileUpload/DokumentListePflichtBeispiel/Upload")]
[AdditionalMetadata(UiMetadata.FileUpload.MaxFiles, "1")]
public DokumentListeViewModel Nachweise { get; set; } = new DokumentListeViewModel();
Wie die Prüfung arbeitet
- Sie sucht am ViewModel die erste Eigenschaft vom Typ
DokumentListeViewModelund prüft derenDokumentIds. Ist die Liste leer odernull, ist das Formular ungültig; die Meldung stammt ausFileUploadValidierungResources.Document_Required. - Zusätzlich wertet sie das versteckte Feld
<Feldname>ExistingDocumentsaus, das das Template immer mitrendert: Sind bereits Dokumente zugeordnet (Bearbeitungsfall), gilt die Bedingung als erfüllt, auch wenn in diesem Durchgang nichts hochgeladen wurde. Dafür wirdIHttpContextAccessorbenötigt, die Registrierung steht unter Vorbedingungen.
Was zu beachten ist
- Die Prüfung läuft serverseitig. Es gibt keinen unaufdringlichen Client-Adapter für
data-val-documentuploadrequired; die Meldung erscheint also erst nach dem Absenden, dann aber beim Feld wie jede andere. Eineasp-validation-summarybraucht es dafür nicht. - Enthält das ViewModel mehrere Eigenschaften vom Typ
DokumentListeViewModel, gewinnt immer die erste. Für mehrere Pflichtlisten in einem Formular ist das Attribut daher nicht geeignet. - Zum Vorführen muss die Liste leer starten. Sind bereits Dokumente vorhanden, greift die
ExistingDocuments-Abkürzung und die Meldung ist nicht mehr auslösbar. - Für eine bedingte Pflicht (nur, wenn ein anderes Feld einen bestimmten Wert hat) gibt es
[DocumentUploadRequiredIf].