Eine Bildergalerie für einen Rich-Text-Editor in Razor Pages

Der Dialog „Insert Gallery“ des Razor-Pages-Beispiels mit den Ordnern blog, products und team und vier hochgeladenen Fotos, eines davon ausgewählt

In einer Razor-Pages-App liegt für die Bildergalerie des Editors zunächst eine Reihe benannter Handler auf der Seite nahe, etwa OnGetGallery und OnPostUpload. Für die Galerie von RichTextEditor sind sie das falsche Werkzeug, aus zwei Gründen, die typisch für Razor Pages sind. Diese Seite zeigt, was Sie stattdessen tun: den Editor auf einer normalen Razor Page und die drei Galerie-Routen als Endpoints in derselben App.

Warum keine Page-Handler

  • Die URLs passen nicht. Ein benannter Handler wird als /?handler=Upload erreicht. Das Upload-Skript des Editors sendet an <base>/upload, und die Galerie hängt für jede Liste ?folder= an galleryEndpoint an, sodass Handler-URLs an beiden Stellen Änderungen bräuchten.
  • Jeder POST-Handler prüft ein Antiforgery-Token. Das ist ein Standard von Razor Pages, und ein guter. Die Requests des Editors für Upload und „New folder“ sind XHRs, die der Editor selbst erzeugt, und das aktuelle Release kann ihnen das Token nicht hinzufügen. Handler bräuchten [IgnoreAntiforgeryToken] am Page Model, was die Prüfung auch für das eigene Save-Formular der Seite abschaltet.

Endpoints halten beides auseinander: Die Seite und ihr Formular behalten den vollen Schutz, und die JSON-Routen treffen ihre eigene, ausdrückliche Entscheidung.

Program.cs

C# · Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();

app.UseStaticFiles();
app.UseRteStaticFiles();   // /uploads, /richtexteditor, /rte-files.js

app.MapRazorPages();       // "/" -> Pages/Index.cshtml; its own form POST keeps antiforgery validation
app.MapRteFiles();         // GET+POST /rte/gallery, POST /rte/upload

app.Run();

MapRteFiles() ist dieselbe Gruppe von Minimal-API-Endpoints, die auch die anderen ASP.NET-Core-Beispiele verwenden: GET und POST /rte/gallery sowie POST /rte/upload. UseRteStaticFiles() liefert /uploads aus (nur die fünf Bildtypen), den Editor unter /richtexteditor und /rte-files.js.

Die Seite

Razor · Pages/Index.cshtml
<link rel="stylesheet" href="/richtexteditor/rte_theme_default.css" />
<script src="/richtexteditor/rte.js"></script>
<script src="/richtexteditor/plugins/all_plugins.js"></script>
<script src="/rte-files.js"></script>

Der Editor wird weiter unten auf der Seite mit galleryEndpoint: "/rte/gallery" erstellt. Bilder aus einem Rich-Text-Editor in Razor Pages hochladen zeigt diesen Teil zusammen mit dem Formular.

Die Route für die Liste

C# · RteEndpoints.cs
rte.MapGet("/gallery", (HttpContext http, string? folder) =>
    Json(RteFiles.List(http, folder)));

Die Antwort ist der Ordner als JSON: currentFolder, parentFolder (null im Stammordner), die Unterordner und die Bilder mit URL, Name und Größe. Es ist dasselbe JSON und derselbe Code wie in der Galerie-Anleitung für ASP.NET Core, die jedes Feld erklärt.

Die POST-Routen und Antiforgery

C# · RteEndpoints.cs
// Binding [FromForm] or IFormFile makes .NET 8 demand an antiforgery token on these endpoints.
// The editor's XHRs cannot send one, so it is switched off here and RteFiles checks the
// request's origin instead (see RequireSameOrigin). guide-notes.md has the details.
rte.MapPost("/gallery", (HttpContext http, [FromForm] string? action, [FromForm] string? folder, [FromForm] string? name) =>
    Json(RteFiles.CreateFolder(http, action, folder, name)))
    .DisableAntiforgery();

Hier kommt das zweite Detail von Razor Pages. AddRazorPages() registriert die Antiforgery-Dienste, fügt in .NET 8 aber nicht die Antiforgery-Middleware hinzu, die Minimal-API-Endpoints verwenden. Ein Endpoint, der IFormFile oder [FromForm] bindet, trägt trotzdem Antiforgery-Metadaten, daher schlug ohne .DisableAntiforgery() jeder POST daran mit einem 500 fehl: „contains anti-forgery metadata, but a middleware was not found that supports anti-forgery“. Fügt man stattdessen app.UseAntiforgery() hinzu, wird daraus ein 400, weil der Editor kein Token sendet. Erst wenn die Prüfung für diese beiden Routen abgeschaltet und stattdessen der Origin des Requests geprüft wird, funktionieren sie. Sicherer Bild-Upload in Razor Pages erklärt diese Prüfung.

Testen

Starten Sie das Beispielprojekt zu dieser Anleitung mit dotnet run (.NET 8 SDK), öffnen Sie http://localhost:5303 und klicken Sie auf Insert Gallery. Der Dialog listet die Ordner und Bilder unter uploads/ auf. In einer Shell antwortet die Upload-Route ohne Token, der eigene POST der Seite dagegen nicht:

Shell
curl -F "file=@photo.jpg" http://localhost:5303/rte/upload
{"url":"/uploads/photo-4cdaeb3e.jpg"}

curl -s -o /dev/null -w "%{http_code}\n" -d "Html=x" http://localhost:5303/
400

Das 400 ist Razor Pages, das einen Formular-POST ohne Antiforgery-Token ablehnt, und genau das wollen Sie für die Seite.

Dieselbe Anleitung für andere Plattformen

JavaScript · Next.js · PHP · ASP.NET Core · Blazor · MVC 5 · Web Forms

Weiterlesen