Das HTML des Rich-Text-Editors in Blazor Server lesen
Früher oder später muss eine Blazor-Server-Seite das HTML des Editors nach C# holen, um es zu speichern. Der naheliegende Aufruf, JS.InvokeAsync<string>, funktioniert beim Testen und scheitert dann beim ersten langen Dokument, weil das Ergebnis über die SignalR-Verbindung der Circuit läuft, die ein Nachrichtenlimit von 32 KB hat. Diese Seite zeigt, was passiert ist, als wir an dieses Limit gestoßen sind, und wie das Beispiel das HTML stattdessen als Stream liest.
Das Limit von 32 KB
In Blazor Server geht jede Nachricht vom Browser an den Server über die Circuit, und das gilt auch für das Ergebnis eines JS-Interop-Aufrufs. MaximumReceiveMessageSize von SignalR ist für die Circuit standardmäßig 32 KB. Wir haben editor.getHTMLCode() über InvokeAsync<string> zurückgegeben und gemessen:
- 20,000 Zeichen HTML: kamen an.
- 40,000 Zeichen: Der Browser protokollierte „Connection disconnected with error 'Error: Server returned an error on close: Connection closed with an error.'“ Die Meldung auf der Seite änderte sich nicht, und die Circuit war weg.
Auf dem Server bleibt der Fehler beim Standard-Loglevel stumm, daher übersieht man ihn beim Testen leicht.
Bytes aus JavaScript zurückgeben
Wenn eine JS-Funktion ein Uint8Array zurückgibt, kann Blazor es als IJSStreamReference an .NET übergeben, das in Chunks außerhalb des Nachrichtenlimits gesendet wird. Die Interop-Funktionen des Beispiels liegen in App.razor:
<script>
// Called from Home.razor. The editor options stay in JavaScript, where they can also hold
// functions (custom buttons, event handlers) that cannot be sent from .NET as JSON.
window.rteBlazor = {
create: function (host) {
host.rte = new RichTextEditor(host, {
toolbar: "full",
galleryEndpoint: "/rte/gallery",
maxUploadFileSize: 4000000 // same limit as the server, checked before the upload starts
});
},
// Returned as bytes: .NET reads them as a stream, so documents over Blazor's 32 KB
// SignalR message limit still arrive.
getHtml: function (host) {
return new TextEncoder().encode(host.rte.getHTMLCode());
},
destroy: function (host) {
if (!host || !host.rte) return;
// editor.destroy() exists only in newer editor builds
if (typeof host.rte.destroy === "function") host.rte.destroy();
host.rte = null;
host.innerHTML = "";
}
};
</script>getHtml kodiert das HTML mit TextEncoder als UTF-8. Den Editor selbst erstellt create; Eine Bildergalerie für einen Rich-Text-Editor in Blazor erklärt create und destroy.
Den Stream in C# lesen
async Task Save()
{
var bytes = await JS.InvokeAsync<IJSStreamReference>("rteBlazor.getHtml", host);
await using var stream = await bytes.OpenReadStreamAsync(maxAllowedSize: 10_000_000);
using var reader = new StreamReader(stream);
var html = await reader.ReadToEndAsync();
message = $"Saved {html.Length} characters of HTML."; // save html to your database here
}InvokeAsync<IJSStreamReference>fordert die Bytes als Stream statt als Wert an.OpenReadStreamAsync(maxAllowedSize: 10_000_000)legt fest, wie viel der Server höchstens liest. Der Standardwert ist 512,000 Bytes, setzen Sie den Wert also auf das, was Ihre Datenbankspalte aufnehmen kann.StreamReaderwandelt die UTF-8-Bytes wieder in einen String um. Speichern Sie ihn von hier aus, und bereinigen Sie ihn, bevor Sie ihn anderen Benutzern anzeigen.
Mit diesem Code kam ein Dokument aus 100,000 x-Zeichen plus einem eingefügten Bild vollständig an: „Saved 100116 characters of HTML.“
Warum nicht das Limit erhöhen
Der andere Ausweg ist ein größeres MaximumReceiveMessageSize in den Hub-Optionen, zum Beispiel über AddInteractiveServerComponents().AddHubOptions(...). Das erhöht das Limit für jede Nachricht in jeder Circuit. Für diese Seite haben wir das weder verwendet noch getestet. Streaming lässt den Standardwert unverändert und lässt nur das HTML durch, bis zu der Größe, die Sie wählen.
Bilder sind ein anderer Fall: Sie gehen überhaupt nicht durch die Komponente. Bilder aus einem Rich-Text-Editor in Blazor hochladen erklärt, warum der Editor sie an HTTP-Endpoints sendet, sodass das gespeicherte HTML nur ihre URLs enthält.
Testen
Starten Sie das Beispielprojekt zu dieser Anleitung mit dotnet run und öffnen Sie http://localhost:5304. Fügen Sie ein langes Dokument in den Editor ein, oder tippen Sie ein paar Absätze und fügen Sie sie viele Male ein, und klicken Sie dann auf Save. Die Meldung unter dem Editor zeigt die Anzahl der Zeichen, die in C# angekommen sind, weit über 32 KB. Um das Limit zu sehen, ändern Sie Save so, dass es das HTML mit InvokeAsync<string> aus einer JS-Funktion liest, die getHTMLCode() als String zurückgibt, und speichern Sie dasselbe Dokument erneut: Die Circuit wird geschlossen.