Projektstruktur für Blazor-Apps
Tipp
Diese Inhalte sind ein Auszug aus dem eBook „Blazor for ASP NET Web Forms Developers for Azure“, verfügbar unter .NET Docs oder als kostenlos herunterladbare PDF-Datei, die offline gelesen werden kann.
Während sich ASP.NET Web Forms und Blazor in der Projektstruktur erheblich unterscheiden, weisen ihre Konzepte viele Gemeinsamkeiten auf. In diesem Artikel wird die Struktur eines Blazor-Projekts mit der eines ASP.NET Web Forms-Projekts verglichen.
Führen Sie die unter Erste Schritte mit Blazor beschriebenen Schritte aus, um Ihre erste Blazor-App zu erstellen. Dort haben Sie die Möglichkeit, entweder eine Blazor Server-App oder eine in ASP.NET Core gehostete Blazor WebAssembly-App zu erstellen. Der größte Teil des Codes ist in beiden Projekten identisch, mit Ausnahme der spezifischen Logik des Hostingmodells.
Projektdatei
Blazor Server-Apps sind .NET-Projekte. Die Projektdatei für die Blazor Server-App ist ganz einfach aufgebaut:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
</PropertyGroup>
</Project>
Die Projektdatei für eine Blazor WebAssembly-App ist etwas komplizierter (die genauen Versionsnummern können variieren):
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.0" PrivateAssets="all" />
</ItemGroup>
</Project>
Blazor WebAssembly-Projekte verwenden Microsoft.NET.Sdk.BlazorWebAssembly
als Ziel (anstelle des SDKs Microsoft.NET.Sdk.Web
), da sie im Browser einer auf WebAssembly basierenden .NET-Runtime ausgeführt werden. .NET kann nicht einfach in einem Webbrowser installiert werden, wie dies auf einem Server oder Entwicklercomputer möglich ist. Daher verweist das Projekt über einzelne Paketverweise auf das Blazor-Framework.
Im Vergleich dazu enthält ein ASP.NET Web Forms-Standardprojekt in seiner CSPROJ-Datei fast 300 Zeilen XML-Code, in dem größtenteils die verschiedenen Code- und Inhaltsdateien des Projekts aufgelistet werden. Seit der Veröffentlichung von .NET 5 können sowohl Blazor-Server als auch BlazorWebAssembly-Apps problemlos eine einheitliche Runtime nutzen.
Einzelne Assemblyverweise werden zwar unterstützt, sind in .NET-Projekten jedoch nicht so häufig. Die meisten Projektabhängigkeiten werden als NuGet-Paketverweise behandelt. In .NET-Projekten müssen Sie nur auf die Paketabhängigkeiten der obersten Ebene verweisen. Transitive Abhängigkeiten werden automatisch eingeschlossen. Zum Hinzufügen von Paketverweisen zur Projektdatei wird das <PackageReference>
-Element verwendet anstelle der Datei „packages.config“ . Diese wird in vielen ASP.NET Web Forms-Projekten zum Verweisen auf Pakete verwendet.
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>
Einstiegspunkt
Der Einstiegspunkt der Blazor Server-App wird in der Datei „Program.cs“ wie in einer Konsolen-App definiert. Wird die App ausgeführt, erstellt sie eine Webhostinstanz basierend auf den für Web-Apps spezifischen Standardeinstellungen, und führt diese aus. Der Webhost verwaltet den Lebenszyklus der Blazor Server-App und richtet Dienste auf Hostebene ein. Zu diesen Diensten gehören z. B. die Konfiguration, Protokollierung, Abhängigkeitsinjektion und der HTTP-Server. Dieser Code besteht größtenteils aus Bausteinen und wird häufig unverändert beibehalten.
using BlazorApp3.Areas.Identity;
using BlazorApp3.Data;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddScoped<AuthenticationStateProvider, RevalidatingIdentityAuthenticationStateProvider<IdentityUser>>();
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
Auch Blazor WebAssembly-Apps definieren in der Datei „Program.cs“ einen Einstiegspunkt. Der Code sieht jedoch etwas anders aus. Die beiden Codes ähneln sich insofern, als dass darin der App-Host für die Bereitstellung derselben Dienste auf Hostebene eingerichtet wird. Ein Unterschied besteht jedoch darin, dass die WebAssembly-App keinen HTTP-Server einrichtet, da sie direkt im Browser ausgeführt wird.
Blazor-Apps verwenden keine Global.asax-Datei, um die Startlogik für die App zu definieren. Stattdessen ist diese Logik in Program.cs oder in einer verknüpften Startup
-Klasse enthalten, auf die von Program.cs verwiesen wird. In beiden Fällen wird dieser Code verwendet, um die App und alle app-spezifischen Dienste zu konfigurieren.
In einer Blazor-Server-App wird die angezeigte Datei Program.cs verwendet, um den Endpunkt für die Echtzeitverbindung einzurichten, die von Blazor zwischen den Clientbrowsern und dem Server verwendet wird.
In einer BlazorWebAssembly-App definiert die Datei Program.cs die Stammkomponenten für die App und den Ort, an dem sie gerendert werden sollen:
using BlazorApp1;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
Statische Dateien
Im Gegensatz zu ASP.NET Web Forms-Projekten können in einem Blazor-Projekt nicht alle Dateien als statische Dateien angefordert werden. Nur die Dateien im Ordner wwwroot sind im Web adressierbar. Dieser Ordner wird als „Webstammverzeichnis“ der App bezeichnet. Dateien, die sich nicht im Webstammverzeichnis der App befinden, sind nicht im Web adressierbar. Diese Einstellung erhöht die Sicherheit, da eine versehentliche Offenlegung von Projektdateien über das Internet verhindert wird.
Konfiguration
Die Konfiguration einer ASP.NET Web Forms-App erfolgt in der Regel über eine oder mehrere web.config-Dateien. Blazor-Apps enthalten in der Regel keine web.config-Dateien. Falls doch, wird diese Datei nur zur Konfiguration von IIS-spezifischen Einstellungen verwendet, sofern die App in IIS gehostet wird. Stattdessen verwenden Blazor Server-Apps die ASP.NET Core-Konfigurationsabstraktionen. (BlazorWebAssembly-Apps unterstützen derzeit nicht dieselben Konfigurationsabstraktionen, aber dies kann ein Feature sein, das in Zukunft hinzugefügt wird.) Beispielsweise speichert die Blazor Server-Standard-App einige Einstellungen in appsettings.json.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Weitere Informationen zur Konfiguration von ASP.NET Core-Projekten finden Sie im Abschnitt Konfiguration.
Razor-Komponenten
Die meisten Dateien in Blazor-Projekten sind RAZOR-Dateien. Razor ist eine auf HTML und C# basierende Sprache zur Vorlagenerstellung, mit der Webbenutzeroberflächen dynamisch erstellt werden. Mit RAZOR-Dateien werden Komponenten definiert, die die Benutzeroberfläche der App bilden. Die meisten dieser Komponenten sind für Blazor Server- und Blazor WebAssembly-Apps identisch. Komponenten in Blazor entsprechen den Benutzersteuerelementen in ASP.NET Web Forms.
Jede Razor-Komponentendatei wird bei der Erstellung des Projekts in eine .NET-Klasse kompiliert. In der generierten Klasse werden Zustand, Renderinglogik, Lebenszyklusmethoden, Ereignishandler und weitere Logik der Komponente gespeichert. Weitere Informationen zum Erstellen von Komponenten finden Sie im Abschnitt Erstellen wiederverwendbarer Benutzeroberflächenkomponenten mit Blazor.
Bei den _Imports.razor-Dateien handelt es sich nicht um Razor-Komponentendateien. Sie definieren vielmehr eine Reihe von Razor-Anweisungen, die in andere RAZOR-Dateien im selben Ordner und dessen Unterordnern importiert werden sollen. So werden mit einer _Imports.razor-Datei z. B. üblicherweise using
-Anweisungen für häufig verwendete Namespaces hinzugefügt:
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using BlazorApp1
@using BlazorApp1.Shared
Seiten
Wo befinden sich in Blazor-Apps die Seiten? Blazor definiert keine separate Dateierweiterung für adressierbare Seiten, wie das in ASP.NET Web Forms-Apps mit ASPX-Dateien der Fall ist. Stattdessen werden Seiten durch Zuweisen von Routen zu Komponenten definiert. Eine Route wird in der Regel mithilfe der Razor-Anweisung @page
zugewiesen. So wird etwa mit der in der Datei „Pages/Counter.razor“ erstellten Komponente Counter
die folgende Route definiert:
@page "/counter"
In Blazor wird das Routing auf der Clientseite verarbeitet, nicht auf dem Server. Navigiert der Benutzer im Browser, fängt Blazor die Navigation ab und rendert die Komponente mit der entsprechenden Route.
Die Komponentenrouten werden derzeit nicht wie bei ASPX-Seiten oder ASP.NET Core Razor Pages vom Dateispeicherort der Komponente abgeleitet. Dieses Feature wird in Zukunft möglicherweise noch hinzugefügt. Jede Route muss für die Komponente explizit angegeben werden. Das Speichern von routingfähigen Komponenten im Ordner Pages hat keine besondere Bedeutung und ist nur eine Konvention.
Weitere Informationen zum Routing in Blazor finden Sie im Abschnitt Seiten, Routing und Layouts.
Layout
In ASP.NET Web Forms-Apps wird das allgemeine Seitenlayout mithilfe von Masterseiten (Site.Master) verarbeitet. In Blazor-Apps wird das Seitenlayout mithilfe von Layoutkomponenten (Shared/MainLayout.razor) behandelt. Layoutkomponenten werden detaillierter im Abschnitt Seiten, Routing und Layouts besprochen.
Bootstrapping für Blazor
Für ein Bootstrapping von Blazor muss die App folgende Aktionen ausführen:
- Angeben der Position, an der die Stammkomponente (App.Razor) auf der Seite gerendert werden soll
- Hinzufügen des entsprechenden Blazor-Frameworkskripts
In der Blazor Server-App wird die Hostseite der Stammkomponente in der Datei „_Host.cshtml“ definiert. Mit dieser Datei wird eine Razor-Seite und keine Komponente definiert. Razor Pages verwendet (ähnlich wie eine ASPX-Seite) zum Definieren einer auf dem Server adressierbaren Seite Razor-Syntax.
@page "/"
@namespace BlazorApp3.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
Layout = "_Layout";
}
<component type="typeof(App)" render-mode="ServerPrerendered" />
Mit dem Attribut render-mode
wird definiert, wo eine Stammkomponente gerendert werden soll. Mit der Option RenderMode
wird der Renderingmodus für die Komponente angegeben. In der folgenden Tabelle werden die unterstützten RenderMode
-Optionen aufgelistet:
Option | BESCHREIBUNG |
---|---|
RenderMode.Server |
Die Komponente wird interaktiv gerendert, sobald eine Verbindung mit dem Browser hergestellt wurde. |
RenderMode.ServerPrerendered |
Die Komponente wird vorab und anschließend interaktiv gerendert. |
RenderMode.Static |
Die Komponente wird als statischer Inhalt gerendert. |
Die Datei _Layout.cshtml enthält den Standard-HTML-Code für die App und ihre Komponenten.
@using Microsoft.AspNetCore.Components.Web
@namespace BlazorApp3.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="~/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link href="css/site.css" rel="stylesheet" />
<link href="BlazorApp3.styles.css" rel="stylesheet" />
<component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
@RenderBody()
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.server.js"></script>
</body>
</html>
Durch den Skriptverweis auf _framework/blazor.server.js wird eine Echtzeitverbindung mit dem Server hergestellt und anschließend alle Benutzerinteraktionen und Aktualisierungen der Benutzeroberfläche verarbeitet.
In der Blazor WebAssembly-App ist die Hostseite eine einfache statische HTML-Datei unter wwwroot/index.html. Über das <div>
-Element mit der ID = app
wird angegeben, wo die Stammkomponente gerendert werden soll.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>BlazorApp1</title>
<base href="/" />
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />
<link href="BlazorApp1.styles.css" rel="stylesheet" />
</head>
<body>
<div id="app">Loading...</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
Die Angabe der zu rendernden Stammkomponente erfolgt über die Datei Program.cs der App, was eine flexible Registrierung von Diensten mittels Abhängigkeitsinjektion ermöglicht. Weitere Informationen finden Sie unter Abhängigkeitsinjektion in ASP.NET Core Blazor.
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
Erstellen der Ausgabe
Beim Erstellen eines Blazor-Projekts werden alle Razor-Komponenten- und Codedateien in einer einzelnen Assembly kompiliert. Im Gegensatz zu ASP.NET Web Forms-Projekten wird in Blazor die Kompilierung von Benutzeroberflächenlogik zur Laufzeit nicht unterstützt.
Ausführen der App mit Hot Reload
Drücken Sie zum Ausführen der Blazor-Server-App F5 in Visual Studio, um mit dem angefügten Debugger auszuführen, oder drücken Sie STRG + F5, um ohne angefügten Debugger auszuführen.
Wählen Sie zum Ausführen der Blazor WebAssembly-App einen der folgenden Ansätze aus:
- Sie können das Clientprojekt direkt mithilfe des Entwicklungsservers ausführen.
- Wenn die App in ASP.NET Core gehostet wird, können Sie das Serverprojekt ausführen.
BlazorWebAssembly-Apps können sowohl im Browser als auch in Visual Studio debuggt werden. Weitere Informationen finden Sie unter Debuggen von ASP.NET Core BlazorWebAssembly.
Sowohl Blazor Server- als auch BlazorWebAssembly-Apps unterstützen Hot Reload in Visual Studio. Hot Reload ist ein Feature, mit dem Änderungen, die an einer Blazor-App vorgenommen werden, automatisch live im Browser aktualisiert werden. Sie können auf der Symbolleiste über das Symbol umschalten, ob Hot Reload aktiviert ist:
Wenn Sie das Caretzeichen neben dem Symbol auswählen, werden zusätzliche Optionen angezeigt. Sie können Hot Reload ein- oder ausschalten, die Anwendung neu starten und umschalten, ob Hot Reload auftreten soll, wenn eine Datei gespeichert wird.
Sie können auch auf zusätzliche Konfigurationsoptionen zugreifen. Im Konfigurationsdialogfeld können Sie angeben, ob Hot Reload beim Debuggen (zusammen mit Bearbeiten und Fortfahren), beim Starten ohne Debuggen oder beim Speichern einer Datei aktiviert werden soll.
Die „innere Entwicklerschleife“ wurde mit Hot Reload erheblich optimiert. Ohne Hot Reload müsste ein Blazor-Entwickler die App in der Regel nach jeder Änderung neu starten und erneut ausführen, um dann nach Bedarf zum entsprechenden Teil der App zu navigieren. Mit Hot Reload können Änderungen an der ausgeführten App vorgenommen werden, ohne dass in den meisten Fällen ein Neustart erforderlich ist. Hot Reload behält sogar den Zustand von Seiten bei, sodass es nicht erforderlich ist, Formularwerte erneut einzugeben oder die App anderweitig an die gewünschte Stelle zu bringen.