Web Forms zu Blazor migrieren: Seite für Seite statt alles auf einmal neu
Eine ASP.NET-Web-Forms-Anwendung Seite für Seite hinter einem Proxy auf Blazor und .NET 10 migrieren: was leicht geht, was schwer ist, wie Sie starten.
Vlado Pandžić · Gründer · Senior .NET-Architekt
Veröffentlicht · 5 Min. Lesezeit
Viele Unternehmen betreiben noch immer eine wichtige Anwendung auf ASP.NET Web Forms: ein Bestellportal, ein internes System für Lager oder Verwaltung, etwas, das seit fünfzehn Jahren läuft. Es läuft immer noch. Aber jede Änderung dauert länger, die Entwickler, die es kennen, gehen, und niemand möchte derjenige sein, der es anfasst.
Die gute Nachricht: Der Umstieg auf Blazor muss kein Jahr Neuentwicklung bedeuten, in dem das Geschäft wartet. Die Anwendung kann Seite für Seite umziehen, während die Nutzer weiterarbeiten und kaum etwas merken.
Warum sich Web Forms nicht einfach aktualisieren lässt
Web Forms gibt es im modernen .NET nicht. Es wurde nie auf ASP.NET Core portiert, also gibt es keinen Knopf „auf .NET 10 aktualisieren“. Die Seiten müssen neu gebaut werden.
.NET Framework 4.8 wird weiterhin so lange unterstützt wie die Windows-Version, auf der es läuft, also schaltet sich morgen nichts ab. Aber es bekommt keine neuen Funktionen, neue Bibliotheken lassen es immer öfter aus, und Entwickler, die in Web Forms arbeiten wollen, sind jedes Jahr schwerer zu finden.
Zwei Wege: alles auf einmal oder Seite für Seite
Alles auf einmal wirkt einfacher: Neben der alten Anwendung wird eine neue gebaut und an einem Tag umgeschaltet. In der Praxis heißt das Monate ohne neue Funktionen in der alten Anwendung, zwei Anwendungen, die parallel gepflegt werden, und ein Go-live, bei dem alles im selben Moment funktionieren muss.
Seite für Seite dreht das um. Vor die alte Anwendung kommt ein Proxy, und jede Seite, die nach Blazor umzieht, wird ab dann von der neuen Anwendung ausgeliefert. Die Nutzer behalten dieselbe Adresse und dieselbe Anmeldung und wechseln von alten zu neuen Seiten, ohne es zu merken.
- 1Bestandsaufnahme aller Seiten
- 2Proxy vor der alten Anwendung
- 3Seite für Seite nach Blazor
- 4Die alte Anwendung wird abgeschaltet
Der Proxy: wie Alt und Neu zusammenarbeiten
Der Proxy ist YARP, der Reverse Proxy von Microsoft, und er läuft in der neuen Blazor-Anwendung. Alles, was die neue Anwendung ausliefern kann, liefert sie selbst aus. Alles andere wird an die alte Web-Forms-Anwendung weitergeleitet.
builder.Services.AddReverseProxy()
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.MapReverseProxy();
In der Konfiguration fängt eine Route alle Adressen ab, mit niedriger Priorität, sodass sie nur greift, wenn keine Blazor-Seite passt:
"ReverseProxy": {
"Routes": {
"webforms": { "ClusterId": "webforms", "Order": 1000, "Match": { "Path": "{**catch-all}" } }
},
"Clusters": {
"webforms": { "Destinations": { "old": { "Address": "https://orders-legacy.internal/" } } }
}
}
Sobald die Auftragsseite in Blazor neu gebaut ist, liefert die neue Anwendung /orders aus, und die alte Seite wird einfach nicht mehr erreicht. Anmeldung und Session lassen sich mit den System.Web-Adaptern von Microsoft zwischen beiden Anwendungen teilen, damit sich niemand zweimal anmelden muss.
Wie eine Seite vorher und nachher aussieht
Eine typische Web-Forms-Tabelle mit Seitenumbruch:
<asp:GridView ID="OrdersGrid" runat="server" AutoGenerateColumns="false"
AllowPaging="true" PageSize="20" OnPageIndexChanging="OrdersGrid_PageIndexChanging">
<Columns>
<asp:BoundField DataField="Number" HeaderText="Order" />
<asp:BoundField DataField="Customer" HeaderText="Customer" />
<asp:BoundField DataField="Total" HeaderText="Total" DataFormatString="{0:C}" />
</Columns>
</asp:GridView>
Dieselbe Seite in Blazor, mit der QuickGrid-Komponente, die mit .NET geliefert wird:
@inject OrderService Orders
<QuickGrid Items="orders" Pagination="pagination">
<PropertyColumn Property="@(o => o.Number)" Title="Order" />
<PropertyColumn Property="@(o => o.Customer)" Title="Customer" />
<PropertyColumn Property="@(o => o.Total)" Title="Total" Format="C" />
</QuickGrid>
<Paginator State="pagination" />
@code {
private readonly PaginationState pagination = new() { ItemsPerPage = 20 };
private IQueryable<Order> orders = Enumerable.Empty<Order>().AsQueryable();
protected override async Task OnInitializedAsync()
=> orders = (await Orders.GetOpenAsync()).AsQueryable();
}
Das Markup sieht ähnlich aus. Der echte Unterschied liegt dahinter: kein ViewState, kein Postback bei jedem Seitenwechsel, und OrderService ist gewöhnliches C#, das sich testen und wiederverwenden lässt.
Was leicht umzieht und was nicht
| In Web Forms | In Blazor | Aufwand |
|---|---|---|
| Geschäftslogik in eigenen Klassen | Dieselben Klassen, als Services | Gering |
| Geschäftslogik im Code-Behind | Wird zuerst in Services herausgelöst | Mittel |
| Master Pages | Layouts | Gering |
| User Controls (.ascx) | Komponenten | Gering bis mittel |
| GridView, Repeater, FormView | QuickGrid oder eine Komponentenbibliothek | Mittel |
| Seiten rund um ViewState und Postbacks | Komponentenzustand, mit neu durchdachtem Ablauf | Mittel |
| Web-Forms-Steuerelemente von Drittanbietern | Deren Blazor-Versionen oder andere Komponenten | Mittel bis hoch |
| Crystal Reports | Ein anderes Reporting-Werkzeug | Hoch |
| Anmeldung und Session für alt und neu gemeinsam | System.Web-Adapter oder ein gemeinsames Cookie | Mittel, einmal zu Beginn |
Die größte Unbekannte ist nicht Blazor, sondern wie viel Logik im Code-Behind vergraben ist. Wo die Logik schon in eigenen Klassen steckt, zieht eine Seite oft in wenigen Tagen um. Wo jeder Button-Klick hundert Zeilen SQL und Oberflächencode vermischt, muss diese Logik erst herausgelöst werden.
In welcher Reihenfolge die Seiten umziehen
- Zuerst eine einfache Seite, um zu beweisen, dass Proxy, Anmeldung und Deployment durchgängig funktionieren.
- Dann die Seiten, die am meisten schmerzen: die sich oft ändern, langsam sind oder über die Nutzer klagen. Dort zahlt sich der Umzug zuerst aus.
- Selten genutzte Verwaltungsseiten zum Schluss. Die Bestandsaufnahme findet oft Seiten, die niemand mehr nutzt, und die müssen gar nicht umziehen.
Checkliste vor dem Start
- Eine Liste aller Seiten, mit Vermerk, welche tatsächlich genutzt werden (Logs oder Analytics).
- NuGet-Pakete und Steuerelemente von Drittanbietern. Unser kostenloses Tool zur .NET-Framework-Migration prüft, welche davon eine Version für .NET 10 haben.
- Wie die Anmeldung heute funktioniert: Forms-Authentifizierung, Windows-Authentifizierung oder ASP.NET Identity.
- Wo die Geschäftslogik liegt: in eigenen Klassen oder im Code-Behind.
- Berichte, Exporte und E-Mails, die die Anwendung versendet.
- Wer jede Seite beim Umzug testet und wer sie abnimmt.
Das größere Bild zum Umstieg von .NET Framework finden Sie im Artikel über den Umstieg von .NET Framework auf .NET 10, und zur Frage, ob Blazor überhaupt eine sichere Wahl ist, Hat Blazor 2026 noch Zukunft?.
Wie wir arbeiten
Genau das machen wir: Wir migrieren Web-Forms-Anwendungen Seite für Seite hinter einem Proxy nach Blazor, während die Nutzer weiter in der Anwendung arbeiten. Wir beginnen mit einer Bestandsaufnahme und einem Plan, der zeigt, welche Seiten zuerst umziehen und wo die schwierigen Teile liegen. Mehr zum Vorgehen steht auf der Seite Blazor, und der erste Schritt ist ein kostenloses 30-minütiges Gespräch.
Quellen
- ASP.NET Framework to ASP.NET Core migration, Microsoft Learn
- Incremental ASP.NET to ASP.NET Core migration, Microsoft Learn
- YARP, GitHub
- System.Web adapters, GitHub
- ASP.NET Core Blazor QuickGrid component, Microsoft Learn
- .NET Framework lifecycle, Microsoft Learn
Dieser Artikel dient nur der allgemeinen Information und ist keine Rechts-, Steuer-, Finanz- oder sonstige Fachberatung. Szenarien, Beispiele und Berechnungen dienen der Veranschaulichung. Nutzungsbedingungen und Haftungsausschluss.