Vor Jahren habe ich schon einmal getestet, wie sich Datei Upload verhält im Vergleich Blazor vs HTML Form. Damals hat ganz klar klassischer HTTP POST per Multipart Formdata gewonnen. Um Faktor 20 und mehr. Eine Datei in 32,5KB Stücken zerhacken und per Websocket zu übertragen ist einen HTTP Post einfach unterlegen. Speziell wenn die Datei sehr groß ist, spielt der HTTP Header Overhead keine Rolle mehr.
Einziger Nachteil war und ist, das eine HTML oder auch Razor cshtml Datei außerhalb des Blazor Kontextes läuft und sich so das Menü und Design nicht teilt.
Nun gibt es mit Blazor 8 ein neuen Rendermode, Static Server Rendering. Damit soll man mehr HTML Stile Websites auf Basis von Blazor erstellen können.
Wenn kein Rendermode spezifiziert ist, wird automatisch SSR genommen. Das muss allerdings auf oberster Ebene in der App.razor passieren indem man den Rendermode einfach entfernt.
In der Page Component kann dann trotzdem wieder Interactive Server genommen werden
1: @page "/upload"
2: @rendermode InteractiveServer
Nun erstellen wir ein Upload Formular wie man es aus HTML kennt. Allerdings benötigt man ein paar Anpassungen für den Blazor renderer.
1: <form method="post" enctype="multipart/form-data"
@formname="Upload1" enhance>
2: <input type="file" name="file" class="form-control" />
3: <button type="submit" class="btn btn-primary mt-3">Upload</button>
4: <AntiforgeryToken></AntiforgeryToken>
5: </form>
Da es mehrere Form Element in einem DOM geben kann, muss der Formname angegeben werden. Er muss eindeutig sein und sonst keinen Zweck erfüllen.
Enhance verhindert das komplette neu laden des DOM und das damit verbundene “flackern”. Mit Enhance wird nach wie vor der komplette HTML Code geladen, allerdings nicht per HTTP Get vom Browser sondern mit dem FETCH Kommando, ausgelöst aus der Blazor Web Java Script Library. Ebendiese Bibliothek tauscht dann nur einzelne DOM Knoten aus.
Um ein Cross Post zu verhindern kommt ein verstecktes Input Feld zum Einsatz, das sogenannte Anti Forgery Token. Für Blazor liefert Microsoft eine gleichnamige Component.
Wie kommt nun Input mit Name file in ein Objekt? Zunächst muss man wissen, das der Objekttyp von Input type File, in ein IFormFile PoCo transformiert wird. Per Attribut und Magie SupplyParamterFromForm wird automatisch der aus dem HTTP Header ausgelesen Feld Input Wert dem .NET Objekt zugewiesen.
[SupplyParameterFromForm] public IFormFile? File { get; set; }
Würde man diese Datei Upload Programmier Aufgabe mit Razor lösen, müsste man das OnPost Event behandeln. In Blazor gibt es nur ein OnInitialize. Hier muss man nur beachten, ob der “Page Load” initial oder durch eine Form Post mit Dateiinhalt ausgelöst wird.
1: protected override async Task OnInitializedAsync()
2: {
3: if (File == null)
4: return;
5: await using var stream =
new FileStream(@"c:\temp\uploadw.bin", FileMode.Create);
6: await File.CopyToAsync(stream);
7: }
Jetzt der spannende Teil. Für eine 100MB Binär Datei, dauert der Upload auf meinen System lokal mit der nativen InputFile Component 4500-4800ms.
Obige SSR Variante 300-350ms. Also ca Faktor 15 schneller!