Delen via


Integreer ASP.NET Core-onderdelen Razor met MVC of Razor Pages in gehoste Blazor WebAssembly oplossingen

Opmerking

Gehoste Blazor WebAssembly oplossingen blijven ondersteund, maar de projectsjabloon is verwijderd en wordt niet meer ondersteund in .NET 8 of hoger. Dit artikel wordt ter referentie weergegeven in de inhoudsopgave tot .NET 7, maar houd er rekening mee dat .NET 7 een Standard Support Term Release is die niet meer wordt ondersteund.

Waarschuwing

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie de .NET- en .NET Core-ondersteuningsbeleidvoor meer informatie.

In dit artikel worden scenario's voor integratie van onderdelen voor gehoste Razor apps uitgelegdBlazor WebAssembly, waaronder het vooraf genereren van Razor onderdelen op de server.

Belangrijk

Frameworkwijzigingen in ASP.NET Core-releases hebben geleid tot verschillende sets instructies in dit artikel. Voordat u de richtlijnen van dit artikel gebruikt, controleert u of de documentversiekiezer boven aan dit artikel overeenkomt met de versie van ASP.NET Core die u voor uw app wilt gebruiken.

Prerendering kan seo (Search Engine Optimization) verbeteren door inhoud weer te geven voor het eerste HTTP-antwoord dat zoekmachines kunnen gebruiken om de paginarang te berekenen.

Oplossingsconfiguratie

Prerenderingsconfiguratie

Prerendering instellen voor een gehoste Blazor WebAssembly app:

  1. Blazor WebAssembly De app hosten in een ASP.NET Core-app. Een zelfstandige Blazor WebAssembly app kan worden toegevoegd aan een ASP.NET Core-oplossing of u kunt een gehoste Blazor WebAssembly app gebruiken die is gemaakt op basis van de Blazor WebAssembly projectsjabloon met de gehoste optie:

    • Visual Studio: Schakel in het dialoogvenster Aanvullende informatie het selectievakje ASP.NET Core Hosted in bij het maken van de Blazor WebAssembly app. In de voorbeelden van dit artikel heeft de oplossing de naam BlazorHosted.
    • Visual Studio Code/.NET CLI-opdrachtshell: dotnet new blazorwasm -ho (gebruik de -ho|--hosted optie). Gebruik de -o|--output {LOCATION} optie om een map voor de oplossing te maken en stel de projectnaamruimten van de oplossing in. In de voorbeelden van dit artikel heeft de oplossing de naam BlazorHosted (dotnet new blazorwasm -ho -o BlazorHosted).

    Voor de voorbeelden in dit artikel is de naam van de gehoste oplossing (assemblynaam) BlazorHosted. De naamruimte van het clientproject is BlazorHosted.Client, en de naamruimte van het serverproject is BlazorHosted.Server.

  2. Verwijder het wwwroot/index.html bestand uit het Blazor WebAssemblyClient project.

  3. Verwijder in het Client project de volgende regels inProgram.cs:

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  4. Voeg _Host.cshtml bestand toe aan de Server map van het Pages project. U kunt de bestanden ophalen uit een project dat is gemaakt op basis van de Blazor Server sjabloon met Visual Studio of met behulp van de .NET CLI met de dotnet new blazorserver -o BlazorServer opdracht in een opdrachtshell (met de -o BlazorServer optie maakt u een map voor het project). Nadat u de bestanden in de map van Server het Pages project hebt geplaatst, moet u de volgende wijzigingen aanbrengen in de bestanden.

    Breng de volgende wijzigingen aan in het _Host.cshtml bestand:

    • Werk de Pages naamruimte boven aan het bestand bij zodat deze overeenkomt met de naamruimte van de pagina's van de Server app. De {APP NAMESPACE} tijdelijke aanduiding in het volgende voorbeeld vertegenwoordigt de naamruimte van de pagina's van de donor-app die het _Host.cshtml bestand heeft geleverd.

      Verwijderen:

      - @namespace {APP NAMESPACE}.Pages
      

      Toevoegen:

      @namespace BlazorHosted.Server.Pages
      
    • Voeg boven aan het bestand een @using richtlijn toe voor het Client project:

      @using BlazorHosted.Client
      
    • Werk de stylesheet-koppelingen bij zodat deze verwijzen naar de stylesheets van het WebAssembly-project. In het volgende voorbeeld is BlazorHosted.Clientde naamruimte van het clientproject. De {APP NAMESPACE} tijdelijke aanduiding vertegenwoordigt de naamruimte van de donor-app die het _Host.cshtml bestand heeft geleverd. Werk de Component Tag Helper (<component> tag) voor de HeadOutlet component bij om de component vooraf te renderen.

      Verwijderen:

      - <link href="css/site.css" rel="stylesheet" />
      - <link href="{APP NAMESPACE}.styles.css" rel="stylesheet" />
      - <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
      

      Toevoegen:

      <link href="css/app.css" rel="stylesheet" />
      <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
      <component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
      

      Opmerking

      Laat het <link> element staan dat het Bootstrap-opmaakmodel (css/bootstrap/bootstrap.min.css) aanvraagt.

    • Werk de Blazor scriptbron bij om het client-side Blazor WebAssembly script te gebruiken.

      Verwijderen:

      - <script src="_framework/blazor.server.js"></script>
      

      Toevoegen:

      <script src="_framework/blazor.webassembly.js"></script>
      
    • Werk de render-mode van de Component Tag Helper bij om de rootcomponent App vooraf te renderen met WebAssemblyPrerendered:

      Verwijderen:

      - <component type="typeof(App)" render-mode="ServerPrerendered" />
      

      Toevoegen:

      <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
      

      Belangrijk

      Prerendering wordt niet ondersteund voor verificatie-eindpunten (/authentication/ padsegment). Zie ASP.NET Core Blazor WebAssembly aanvullende beveiligingsscenario'svoor meer informatie.

  5. Wijzig in het Program.cs bestand van het Server project het fallback-endpoint van het index.html bestand naar de _Host.cshtml pagina.

    Verwijderen:

    - app.MapFallbackToFile("index.html");
    

    Toevoegen:

    app.MapFallbackToPage("/_Host");
    
  6. Als de Client en Server projecten een of meer algemene services gebruiken tijdens het prerendering, moet u rekening houden met de serviceregistraties in een methode die vanuit beide projecten kan worden aangeroepen. Zie ASP.NET Core Blazor dependency injectionvoor meer informatie.

  7. Voer het Server project uit. De gehoste Blazor WebAssembly app wordt vooraf gerenderd door het Server project voor klanten.

Configuratie voor het insluiten van Razor onderdelen in pagina's of weergaven

Voor de volgende secties en voorbeelden voor het insluiten van Razor onderdelen van de ClientBlazor WebAssembly app in pagina's of weergaven van de server-app is extra configuratie vereist.

Het Server project moet de volgende bestanden en mappen hebben.

Razor Bladzijden:

  • Pages/Shared/_Layout.cshtml
  • Pages/Shared/_Layout.cshtml.css
  • Pages/_ViewImports.cshtml
  • Pages/_ViewStart.cshtml

MVC:

  • Views/Shared/_Layout.cshtml
  • Views/Shared/_Layout.cshtml.css
  • Views/_ViewImports.cshtml
  • Views/_ViewStart.cshtml

De voorgaande bestanden kunnen worden verkregen door een app te genereren op basis van de ASP.NET Core-projectsjablonen met behulp van:

  • De nieuwe hulpprogramma's voor het maken van projecten in Visual Studio.
  • Een opdrachtshell openen en uitvoeren dotnet new webapp -o {PROJECT NAME} (Razor Pagina's) of dotnet new mvc -o {PROJECT NAME} (MVC). De optie -o|--output met een waarde voor de {PROJECT NAME} tijdelijke aanduiding bevat een naam voor de app en maakt een map voor de app.

Werk de naamruimten in het geïmporteerde _ViewImports.cshtml bestand bij zodat deze overeenkomen met de naamruimten die worden gebruikt door het Server project dat de bestanden ontvangt.

Pages/_ViewImports.cshtml (Razor Pagina's):

@using BlazorHosted.Server
@namespace BlazorHosted.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Views/_ViewImports.cshtml (MVC):

@using BlazorHosted.Server
@using BlazorHosted.Server.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Werk het geïmporteerde indelingsbestand bij, dat Pages/Shared/_Layout.cshtml is voor Razor pagina's of Views/Shared/_Layout.cshtml voor MVC.

Verwijder eerst de titel en het opmaakmodel uit het donorproject, dat in het volgende voorbeeld RPDonor.styles.css is. De {PROJECT NAME} tijdelijke aanduiding vertegenwoordigt de app-naam van het donorproject.

- <title>@ViewData["Title"] - {PROJECT NAME}</title>
- <link rel="stylesheet" href="~/RPDonor.styles.css" asp-append-version="true" />

Neem de stijlen van het Client project op in het indelingsbestand. In het volgende voorbeeld is Clientde naamruimte van het BlazorHosted.Client project. Het <title> element kan tegelijkertijd worden bijgewerkt.

Plaats de volgende regels in de <head> inhoud van het indelingsbestand:

<title>@ViewData["Title"] - BlazorHosted</title>
<link href="css/app.css" rel="stylesheet" />
<link rel="stylesheet" href="BlazorHosted.Client.styles.css" asp-append-version="true" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />

De geïmporteerde indeling bevat twee Home (Index pagina) en Privacy navigatiekoppelingen. Als u de Home koppelingen naar de gehoste Blazor WebAssembly app wilt laten verwijzen, wijzigt u de hyperlinks:

- <a class="navbar-brand" asp-area="" asp-page="/Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

In een MVC-indelingsbestand:

- <a class="navbar-brand" asp-area="" asp-controller="Home" 
-     asp-action="Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-controller="Home" 
-     asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

Werk de app-naam van het <footer> element bij. In het volgende voorbeeld wordt de naam BlazorHostedvan de app gebruikt:

- &copy; {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ &copy; {DATE} - BlazorHosted - <a asp-area="" asp-page="/Privacy">Privacy</a>

In het voorgaande voorbeeld vertegenwoordigt de {DATE} tijdelijke aanduiding de copyrightdatum in een app gegenereerd vanuit de Razor Pages- of MVC-projectsjabloon.

Als u de Privacy koppeling wilt laten leiden tot een privacypagina (Razor Pagina's), voegt u een privacypagina toe aan het Server project.

Pages/Privacy.cshtml in het Server project:

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

Voor een privacyweergave op basis van MVC maakt u een privacyweergave in het Server project.

View/Home/Privacy.cshtml in het Server project:

@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

Retourneer de weergave in de Home controller van de MVC-app.

Voeg de volgende code toe aan Controllers/HomeController.cs:

public IActionResult Privacy()
{
    return View();
}

Als u bestanden uit een donor-app importeert, moet u alle naamruimten in de bestanden bijwerken zodat deze overeenkomen met die van het Server project (bijvoorbeeld BlazorHosted.Server).

Importeer statische assets naar het Server project vanuit de wwwroot map van het donorproject.

  • wwwroot/css map en inhoud
  • wwwroot/js map en inhoud
  • wwwroot/lib map en inhoud

Als het donorproject wordt gemaakt op basis van een ASP.NET Core-projectsjabloon en de bestanden niet worden gewijzigd, kunt u de hele wwwroot map van het donorproject naar het Server project kopiëren en het favicon pictogrambestand verwijderen.

Waarschuwing

Vermijd het plaatsen van de statische asset zowel in de Client map als in de Serverwwwroot mappen. Als hetzelfde bestand in beide mappen aanwezig is, wordt er een uitzondering gegenereerd omdat de statische assets hetzelfde webhoofdpad delen. Host daarom een statische asset in een van de wwwroot mappen, niet beide.

Nadat u de voorgaande configuratie hebt aangenomen, kunt u Razor-onderdelen insluiten in pagina's of weergaven van het Server-project. Gebruik de richtlijnen in de volgende secties van dit artikel:

  • Onderdelen weergeven in een pagina of weergave met de Helper voor onderdeeltags
  • Onderdelen weergeven in een pagina of weergave met een CSS-selector

Onderdelen weergeven in een pagina of weergave met de Helper voor onderdeeltags

Nadat u de oplossing hebt geconfigureerd, inclusief de aanvullende configuratie, ondersteunt de Tag Helper voor onderdelen twee rendermodi voor het weergeven van een onderdeel vanuit een Blazor WebAssembly app in een pagina of weergave:

In het volgende Razor paginavoorbeeld wordt het Counter onderdeel weergegeven op een pagina. Als u het onderdeel interactief wilt maken, wordt het Blazor WebAssembly script opgenomen in de weergavesectie van de pagina. Als u wilt voorkomen dat u de volledige naamruimte voor het Counter onderdeel gebruikt met de Component Tag Helper ({ASSEMBLY NAME}.Pages.Counter), voegt u een @using instructie toe voor de naamruimte van Pages het clientproject. In het volgende voorbeeld is Clientde naamruimte van het BlazorHosted.Client project.

In het Server project: Pages/RazorPagesCounter1.cshtml

@page
@using BlazorHosted.Client.Pages

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Voer het Server project uit. Navigeer naar de Razor pagina op /razorpagescounter1. Het vooraf gegenereerde Counter onderdeel wordt ingesloten in de pagina.

RenderMode hiermee configureert u of het onderdeel:

  • Wordt vooraf in de pagina weergegeven.
  • Wordt weergegeven als statische HTML op de pagina of als deze de benodigde informatie bevat voor het opstarten van een Blazor app van de gebruikersagent.

Zie Component RenderMode voor meer informatie over de Component Tag Helper, inclusief het doorgeven van parameters en configuratie.

Mogelijk is er extra werk vereist, afhankelijk van de statische resources die onderdelen gebruiken en hoe indelingspagina's in een app worden ingedeeld. Scripts worden doorgaans toegevoegd aan de rendersectie van een pagina of weergave Scripts en stylesheets worden toegevoegd aan de inhoud van het <head> element van de indeling.

Instellen van kindinhoud via een renderfragment

De Component Tag Helper biedt geen ondersteuning om een RenderFragment delegate voor child content te ontvangen (bijvoorbeeld param-ChildContent="..."). We raden je aan een Razor component (.razor) te maken dat verwijst naar de component die je wilt weergeven met de child-inhoud die je wilt doorgeven en vervolgens het Razor component aan te roepen vanaf de pagina of weergave.

Zorg ervoor dat vooraf samengestelde onderdelen op het hoogste niveau niet zijn afgekapt bij publiceren

Als een Helper voor onderdeeltags rechtstreeks verwijst naar een onderdeel uit een bibliotheek waarvoor het bij het publiceren moet worden ingekort, kan het onderdeel tijdens het publiceren worden afgekapt omdat er geen verwijzingen naar zijn vanuit app-code aan de clientzijde. Als gevolg hiervan wordt het onderdeel niet vooraf gerendeerd, waarbij een lege plek in de uitvoer achterblijft. Als dit gebeurt, geeft u de trimmer de instructie om het bibliotheekonderdeel te behouden door een DynamicDependency kenmerk toe te voegen aan een klasse in de app aan de clientzijde. Als u een onderdeel wilt behouden dat wordt aangeroepen SomeLibraryComponentToBePreserved, voegt u het volgende toe aan een onderdeel:

@using System.Diagnostics.CodeAnalysis
@attribute [DynamicDependency(DynamicallyAccessedMemberTypes.All, 
    typeof(SomeLibraryComponentToBePreserved))]

De voorgaande benadering is meestal niet vereist, omdat de app meestal de onderdelen voorafzet (die niet zijn ingekort), die op zijn beurt verwijst naar onderdelen uit bibliotheken (waardoor ze ook niet worden afgekapt). DynamicDependency Gebruik alleen expliciet voor het prerenderen van een bibliotheekonderdeel rechtstreeks wanneer de bibliotheek onderhevig is aan bijsnijden.

Onderdelen weergeven in een pagina of weergave met een CSS-selector

Voeg na het configureren van de oplossing, inclusief de aanvullende configuratie, hoofdonderdelen toe aan het Client project van een gehoste Blazor WebAssembly oplossing in het Program.cs bestand. In het volgende voorbeeld wordt het Counter onderdeel gedeclareerd als een hoofdonderdeel met een CSS-selector die het element selecteert met het id element dat overeenkomt counter-component. In het volgende voorbeeld is Clientde naamruimte van het BlazorHosted.Client project.

In het bestand Program.cs van het project Client, voeg de namespace voor de Razor-componenten toe aan het begin van het bestand.

using BlazorHosted.Client.Pages;

Nadat het builder onderdeel is gemaakt in Program.cs, voegt u het Counter onderdeel toe als basiscomponent.

builder.RootComponents.Add<Counter>("#counter-component");

In het volgende Razor paginavoorbeeld wordt het Counter onderdeel weergegeven op een pagina. Als u het onderdeel interactief wilt maken, wordt het Blazor WebAssembly script opgenomen in de weergavesectie van de pagina.

In het Server project: Pages/RazorPagesCounter2.cshtml

@page

<div id="counter-component">Loading...</div>

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Voer het Server project uit. Navigeer naar de Razor pagina op /razorpagescounter2. Het vooraf gegenereerde Counter onderdeel wordt ingesloten in de pagina.

Mogelijk is er extra werk vereist, afhankelijk van de statische resources die onderdelen gebruiken en hoe indelingspagina's in een app worden ingedeeld. Scripts worden doorgaans toegevoegd aan de rendersectie van een pagina of weergave Scripts en stylesheets worden toegevoegd aan de inhoud van het <head> element van de indeling.

Opmerking

In het voorgaande voorbeeld doet een JSException zich voor indien een Blazor WebAssembly-app vooraf wordt gerenderd en geïntegreerd in een Razor Pages- of MVC-app gelijktijdig met gebruik van een CSS-selector. Als u naar een van de onderdelen van het Client project Razor navigeert of naar een pagina of weergave van het Server met een ingesloten onderdeel navigeert, wordt een of meer JSExceptiononderdelen gegenereerd.

Dit is normaal gedrag omdat het prerenderen en integreren van een Blazor WebAssembly app met routeerbare Razor onderdelen niet compatibel is met het gebruik van CSS-selectors.

Als u met de voorbeelden in de voorgaande secties hebt gewerkt en alleen de CSS-selector in uw voorbeeld-app wilt zien, markeert u de specificatie van het App hoofdonderdeel van het Client projectbestand Program.cs :

- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");

Navigeer naar de pagina of weergave met het ingesloten Razor onderdeel dat gebruikmaakt van een CSS-selector (bijvoorbeeld /razorpagescounter2 van het vorige voorbeeld). De pagina of weergave wordt geladen met het ingesloten onderdeel en het ingesloten onderdeel werkt zoals verwacht.

Voorgeconfigureerde status behouden

Zonder dat de vooraf gegenereerde status behouden blijft, gaat de status die tijdens het prerenderen wordt gebruikt verloren en moet deze opnieuw worden gemaakt wanneer de app volledig is geladen. Als een toestand asynchroon is ingesteld, kan de gebruikersinterface flikkeren doordat de vooraf gerenderde gebruikersinterface wordt vervangen door tijdelijke aanduidingen en vervolgens weer volledig wordt weergegeven.

Als u de status wilt behouden voor vooraf gegenereerde onderdelen, gebruikt u de Helper voor persistente statustags (referentiebron). Voeg de tag van de Tag Helper, <persist-component-state />, toe binnen in de afsluitende </body> tag van de _Host pagina in een app die componenten prerendert.

Opmerking

Documentatiekoppelingen naar .NET-referentiebron laden meestal de standaardbranch van de opslagplaats, die de huidige ontwikkeling vertegenwoordigt voor de volgende release van .NET. Als u een tag voor een specifieke release wilt selecteren, gebruikt u de Switch branches of tags vervolgkeuzelijst. Zie Een versietag selecteren van ASP.NET Core-broncode (dotnet/AspNetCore.Docs #26205)voor meer informatie.

In Pages/_Host.cshtml van Blazor apps die WebAssembly-voorgerenderd zijn (WebAssemblyPrerendered) in een gehoste Blazor WebAssembly app:

<body>
    ...

    <persist-component-state />
</body>

Bepaal welke status moet worden behouden met behulp van de PersistentComponentState service. PersistentComponentState.RegisterOnPersisting registreert een callback om de onderdeelstatus te behouden voordat de app wordt onderbroken. De status wordt opgehaald wanneer de toepassing wordt hervat. Maak de aanroep aan het einde van de initialisatiecode om tijdens het afsluiten van de app een potentiële raceconditie te voorkomen.

In het volgende voorbeeld:

  • De {TYPE} tijdelijke aanduiding vertegenwoordigt het type gegevens dat moet worden bewaard (bijvoorbeeld WeatherForecast[]).
  • De {TOKEN} placeholder is een staat-identificatiestring (bijvoorbeeld, fetchdata).
@implements IDisposable
@inject PersistentComponentState ApplicationState

...

@code {
    private {TYPE} data;
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        if (!ApplicationState.TryTakeFromJson<{TYPE}>(
            "{TOKEN}", out var restored))
        {
            data = await ...;
        }
        else
        {
            data = restored!;
        }

        // Call at the end to avoid a potential race condition at app shutdown
        persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson("{TOKEN}", data);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

Het volgende voorbeeld is een bijgewerkte versie van het FetchData onderdeel in een gehoste Blazor WebAssembly app op basis van de Blazor projectsjabloon. Het WeatherForecastPreserveState onderdeel blijft de weersvoorspellingsstatus behouden tijdens het prerenderen en haalt vervolgens de status op om het onderdeel te initialiseren. De Helper voor persistente onderdeelstatustags blijft de status van het onderdeel behouden na alle aanroepen van onderdelen.

Pages/WeatherForecastPreserveState.razor:

@page "/weather-forecast-preserve-state"
@using BlazorSample.Shared
@implements IDisposable
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState

<PageTitle>Weather Forecast</PageTitle>

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
            nameof(forecasts), out var restored))
        {
            forecasts = await WeatherForecastService.GetForecastAsync(
                DateOnly.FromDateTime(DateTime.Now));
        }
        else
        {
            forecasts = restored!;
        }

        // Call at the end to avoid a potential race condition at app shutdown
        persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson(nameof(forecasts), forecasts);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

Door onderdelen te initialiseren met dezelfde status die tijdens het prerenderen wordt gebruikt, worden dure initialisatiestappen slechts één keer uitgevoerd. De gerenderde gebruikersinterface komt ook overeen met de vooraf gegenereerde gebruikersinterface, dus er treedt geen flikkering op in de browser.

De persistente vooraf gegenereerde status wordt overgebracht naar de client, waar deze wordt gebruikt om de status van het onderdeel te herstellen. Voor prerendering in een gehoste Blazor WebAssembly app worden de gegevens blootgesteld aan de browser en mogen ze geen gevoelige, persoonlijke gegevens bevatten.

Aanvullende Blazor WebAssembly informatiebronnen

Prerendering kan seo (Search Engine Optimization) verbeteren door inhoud weer te geven voor het eerste HTTP-antwoord dat zoekmachines kunnen gebruiken om de paginarang te berekenen.

Oplossingsconfiguratie

Prerenderingsconfiguratie

Prerendering instellen voor een gehoste Blazor WebAssembly app:

  1. Blazor WebAssembly De app hosten in een ASP.NET Core-app. Een zelfstandige Blazor WebAssembly app kan worden toegevoegd aan een ASP.NET Core-oplossing of u kunt een gehoste Blazor WebAssembly app gebruiken die is gemaakt op basis van de Blazor WebAssembly projectsjabloon met de gehoste optie:

    • Visual Studio: Schakel in het dialoogvenster Aanvullende informatie het selectievakje ASP.NET Core Hosted in bij het maken van de Blazor WebAssembly app. In de voorbeelden van dit artikel heeft de oplossing de naam BlazorHosted.
    • Visual Studio Code/.NET CLI-opdrachtshell: dotnet new blazorwasm -ho (gebruik de -ho|--hosted optie). Gebruik de -o|--output {LOCATION} optie om een map voor de oplossing te maken en stel de projectnaamruimten van de oplossing in. In de voorbeelden van dit artikel heeft de oplossing de naam BlazorHosted (dotnet new blazorwasm -ho -o BlazorHosted).

    Voor de voorbeelden in dit artikel is de naamruimte van het clientproject BlazorHosted.Client, en de naamruimte van het serverproject is BlazorHosted.Server.

  2. Verwijder het wwwroot/index.html bestand uit het Blazor WebAssemblyClient project.

  3. Verwijder in het Client project de volgende regels inProgram.cs:

    - builder.RootComponents.Add<App>("#app");
    - builder.RootComponents.Add<HeadOutlet>("head::after");
    
  4. Voeg _Host.cshtml en _Layout.cshtml bestanden toe aan de Server map van het Pages project. U kunt de bestanden ophalen uit een project dat is gemaakt op basis van de Blazor Server sjabloon met Visual Studio of met behulp van de .NET CLI met de dotnet new blazorserver -o BlazorServer opdracht in een opdrachtshell (met de -o BlazorServer optie maakt u een map voor het project). Nadat u de bestanden in de map van Server het Pages project hebt geplaatst, moet u de volgende wijzigingen aanbrengen in de bestanden.

    Belangrijk

    Het gebruik van een indelingspagina (_Layout.cshtml) met een Component Tag Helper voor een HeadOutlet onderdeel is vereist voor het beheren <head> van inhoud, zoals de titel (PageTitle component) van de pagina en andere hoofdelementen (HeadContent onderdeel). Zie Hoofdinhoud beheren in ASP.NET Core-apps Blazorvoor meer informatie.

    Breng de volgende wijzigingen aan in het _Layout.cshtml bestand:

    • Werk de Pages naamruimte boven aan het bestand bij zodat deze overeenkomt met de naamruimte van de pagina's van de Server app. De {APP NAMESPACE} tijdelijke aanduiding in het volgende voorbeeld vertegenwoordigt de naamruimte van de pagina's van de donor-app die het _Layout.cshtml bestand heeft geleverd.

      Verwijderen:

      - @namespace {APP NAMESPACE}.Pages
      

      Toevoegen:

      @namespace BlazorHosted.Server.Pages
      
    • Voeg boven aan het bestand een @using richtlijn toe voor het Client project:

      @using BlazorHosted.Client
      
    • Werk de stylesheet-koppelingen bij zodat deze verwijzen naar de stylesheets van het WebAssembly-project. In het volgende voorbeeld is BlazorHosted.Clientde naamruimte van het clientproject. De {APP NAMESPACE} tijdelijke aanduiding vertegenwoordigt de naamruimte van de donor-app die het _Layout.cshtml bestand heeft geleverd. Werk de Component Tag Helper (<component> tag) voor de HeadOutlet component bij om de component vooraf te renderen.

      Verwijderen:

      - <link href="css/site.css" rel="stylesheet" />
      - <link href="{APP NAMESPACE}.styles.css" rel="stylesheet" />
      - <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
      

      Toevoegen:

      <link href="css/app.css" rel="stylesheet" />
      <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
      <component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />
      

      Opmerking

      Laat het <link> element staan dat het Bootstrap-opmaakmodel (css/bootstrap/bootstrap.min.css) aanvraagt.

    • Werk de Blazor scriptbron bij om het client-side Blazor WebAssembly script te gebruiken.

      Verwijderen:

      - <script src="_framework/blazor.server.js"></script>
      

      Toevoegen:

      <script src="_framework/blazor.webassembly.js"></script>
      

    In het bestand _Host.cshtml:

    • Wijzig de Pages naamruimte in die van het Client project. De {APP NAMESPACE} placeholder vertegenwoordigt de naamruimte van de pagina's van de donor-app die het _Host.cshtml bestand heeft geleverd.

      Verwijderen:

      - @namespace {APP NAMESPACE}.Pages
      

      Toevoegen:

      @namespace BlazorHosted.Client
      
    • Werk de render-mode van de Component Tag Helper bij om de rootcomponent App vooraf te renderen met WebAssemblyPrerendered:

      Verwijderen:

      - <component type="typeof(App)" render-mode="ServerPrerendered" />
      

      Toevoegen:

      <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
      

      Belangrijk

      Prerendering wordt niet ondersteund voor verificatie-eindpunten (/authentication/ padsegment). Zie ASP.NET Core Blazor WebAssembly aanvullende beveiligingsscenario'svoor meer informatie.

  5. In de eindpunttoewijzing van het Server project in Program.cs, wijzig de terugval van het index.html bestand naar de _Host.cshtml pagina.

    Verwijderen:

    - app.MapFallbackToFile("index.html");
    

    Toevoegen:

    app.MapFallbackToPage("/_Host");
    
  6. Als de Client en Server projecten een of meer algemene services gebruiken tijdens het prerendering, moet u rekening houden met de serviceregistraties in een methode die vanuit beide projecten kan worden aangeroepen. Zie ASP.NET Core Blazor dependency injectionvoor meer informatie.

  7. Voer het Server project uit. De gehoste Blazor WebAssembly app wordt vooraf gerenderd door het Server project voor klanten.

Configuratie voor het insluiten van Razor onderdelen in pagina's of weergaven

Voor de volgende secties en voorbeelden voor het insluiten van Razor onderdelen van de ClientBlazor WebAssembly app in pagina's of weergaven van de server-app is extra configuratie vereist.

Het Server project moet de volgende bestanden en mappen hebben.

Razor Bladzijden:

  • Pages/Shared/_Layout.cshtml
  • Pages/Shared/_Layout.cshtml.css
  • Pages/_ViewImports.cshtml
  • Pages/_ViewStart.cshtml

MVC:

  • Views/Shared/_Layout.cshtml
  • Views/Shared/_Layout.cshtml.css
  • Views/_ViewImports.cshtml
  • Views/_ViewStart.cshtml

Belangrijk

Het gebruik van een indelingspagina (_Layout.cshtml) met een Component Tag Helper voor een HeadOutlet onderdeel is vereist voor het beheren <head> van inhoud, zoals de titel (PageTitle component) van de pagina en andere hoofdelementen (HeadContent onderdeel). Zie Hoofdinhoud beheren in ASP.NET Core-apps Blazorvoor meer informatie.

De voorgaande bestanden kunnen worden verkregen door een app te genereren op basis van de ASP.NET Core-projectsjablonen met behulp van:

  • De nieuwe hulpprogramma's voor het maken van projecten in Visual Studio.
  • Een opdrachtshell openen en uitvoeren dotnet new webapp -o {PROJECT NAME} (Razor Pagina's) of dotnet new mvc -o {PROJECT NAME} (MVC). De optie -o|--output met een waarde voor de {PROJECT NAME} tijdelijke aanduiding bevat een naam voor de app en maakt een map voor de app.

Werk de naamruimten in het geïmporteerde _ViewImports.cshtml bestand bij zodat deze overeenkomen met de naamruimten die worden gebruikt door het Server project dat de bestanden ontvangt.

Pages/_ViewImports.cshtml (Razor Pagina's):

@using BlazorHosted.Server
@namespace BlazorHosted.Server.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Views/_ViewImports.cshtml (MVC):

@using BlazorHosted.Server
@using BlazorHosted.Server.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

Werk het geïmporteerde indelingsbestand bij, dat Pages/Shared/_Layout.cshtml is voor Razor pagina's of Views/Shared/_Layout.cshtml voor MVC.

Verwijder eerst de titel en het opmaakmodel uit het donorproject, dat in het volgende voorbeeld RPDonor.styles.css is. De {PROJECT NAME} tijdelijke aanduiding vertegenwoordigt de app-naam van het donorproject.

- <title>@ViewData["Title"] - {PROJECT NAME}</title>
- <link rel="stylesheet" href="~/RPDonor.styles.css" asp-append-version="true" />

Neem de stijlen van het Client project op in het indelingsbestand. In het volgende voorbeeld is Clientde naamruimte van het BlazorHosted.Client project. Het <title> element kan tegelijkertijd worden bijgewerkt.

Plaats de volgende regels in de <head> inhoud van het indelingsbestand:

<title>@ViewData["Title"] - BlazorHosted</title>
<link href="css/app.css" rel="stylesheet" />
<link rel="stylesheet" href="BlazorHosted.Client.styles.css" asp-append-version="true" />
<component type="typeof(HeadOutlet)" render-mode="WebAssemblyPrerendered" />

De geïmporteerde indeling bevat twee Home (Index pagina) en Privacy navigatiekoppelingen. Als u de Home koppelingen naar de gehoste Blazor WebAssembly app wilt laten verwijzen, wijzigt u de hyperlinks:

- <a class="navbar-brand" asp-area="" asp-page="/Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

In een MVC-indelingsbestand:

- <a class="navbar-brand" asp-area="" asp-controller="Home" 
-     asp-action="Index">{PROJECT NAME}</a>
+ <a class="navbar-brand" href="/">BlazorHosted</a>
- <a class="nav-link text-dark" asp-area="" asp-controller="Home" 
-     asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

Werk de app-naam van het <footer> element bij. In het volgende voorbeeld wordt de naam BlazorHostedvan de app gebruikt:

- &copy; {DATE} - {DONOR NAME} - <a asp-area="" asp-page="/Privacy">Privacy</a>
+ &copy; {DATE} - BlazorHosted - <a asp-area="" asp-page="/Privacy">Privacy</a>

In het voorgaande voorbeeld vertegenwoordigt de {DATE} tijdelijke aanduiding de copyrightdatum in een app gegenereerd vanuit de Razor Pages- of MVC-projectsjabloon.

Als u de Privacy koppeling wilt laten leiden tot een privacypagina (Razor Pagina's), voegt u een privacypagina toe aan het Server project.

Pages/Privacy.cshtml in het Server project:

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

Voor een privacyweergave op basis van MVC maakt u een privacyweergave in het Server project.

View/Home/Privacy.cshtml in het Server project:

@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p>Use this page to detail your site's privacy policy.</p>

Retourneer de weergave in de Home controller van de MVC-app.

Voeg de volgende code toe aan Controllers/HomeController.cs:

public IActionResult Privacy()
{
    return View();
}

Als u bestanden uit een donor-app importeert, moet u alle naamruimten in de bestanden bijwerken zodat deze overeenkomen met die van het Server project (bijvoorbeeld BlazorHosted.Server).

Importeer statische assets naar het Server project vanuit de wwwroot map van het donorproject.

  • wwwroot/css map en inhoud
  • wwwroot/js map en inhoud
  • wwwroot/lib map en inhoud

Als het donorproject wordt gemaakt op basis van een ASP.NET Core-projectsjabloon en de bestanden niet worden gewijzigd, kunt u de hele wwwroot map van het donorproject naar het Server project kopiëren en het favicon pictogrambestand verwijderen.

Waarschuwing

Vermijd het plaatsen van de statische asset zowel in de Client map als in de Serverwwwroot mappen. Als hetzelfde bestand in beide mappen aanwezig is, wordt er een uitzondering gegenereerd omdat de statische asset in elke map hetzelfde webhoofdpad deelt. Host daarom een statische asset in een van beide wwwroot mappen, niet beide.

Nadat u de voorgaande configuratie hebt aangenomen, kunt u Razor-onderdelen insluiten in pagina's of weergaven van het Server-project. Gebruik de richtlijnen in de volgende secties van dit artikel:

  • Onderdelen weergeven in een pagina of weergave met de Helper voor onderdeeltags
  • Onderdelen weergeven in een pagina of weergave met een CSS-selector

Onderdelen weergeven in een pagina of weergave met de Helper voor onderdeeltags

Nadat u de oplossing hebt geconfigureerd, inclusief de aanvullende configuratie, ondersteunt de Tag Helper voor onderdelen twee rendermodi voor het weergeven van een onderdeel vanuit een Blazor WebAssembly app in een pagina of weergave:

In het volgende Razor paginavoorbeeld wordt het Counter onderdeel weergegeven op een pagina. Als u het onderdeel interactief wilt maken, wordt het Blazor WebAssembly script opgenomen in de weergavesectie van de pagina. Als u wilt voorkomen dat u de volledige naamruimte voor het Counter onderdeel gebruikt met de Component Tag Helper ({ASSEMBLY NAME}.Pages.Counter), voegt u een @using instructie toe voor de naamruimte van Pages het clientproject. In het volgende voorbeeld is Clientde naamruimte van het BlazorHosted.Client project.

In het Server project: Pages/RazorPagesCounter1.cshtml

@page
@using BlazorHosted.Client.Pages

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Voer het Server project uit. Navigeer naar de Razor pagina op /razorpagescounter1. Het vooraf gegenereerde Counter onderdeel wordt ingesloten in de pagina.

RenderMode hiermee configureert u of het onderdeel:

  • Wordt vooraf in de pagina weergegeven.
  • Wordt weergegeven als statische HTML op de pagina of als deze de benodigde informatie bevat voor het opstarten van een Blazor app van de gebruikersagent.

Zie Component RenderMode voor meer informatie over de Component Tag Helper, inclusief het doorgeven van parameters en configuratie.

Mogelijk is er extra werk vereist, afhankelijk van de statische resources die onderdelen gebruiken en hoe indelingspagina's in een app worden ingedeeld. Scripts worden doorgaans toegevoegd aan de rendersectie van een pagina of weergave Scripts en stylesheets worden toegevoegd aan de inhoud van het <head> element van de indeling.

Instellen van kindinhoud via een renderfragment

De Component Tag Helper biedt geen ondersteuning om een RenderFragment delegate voor child content te ontvangen (bijvoorbeeld param-ChildContent="..."). We raden je aan een Razor component (.razor) te maken dat verwijst naar de component die je wilt weergeven met de child-inhoud die je wilt doorgeven en vervolgens het Razor component aan te roepen vanaf de pagina of weergave.

Zorg ervoor dat vooraf samengestelde onderdelen op het hoogste niveau niet zijn afgekapt bij publiceren

Als een Helper voor onderdeeltags rechtstreeks verwijst naar een onderdeel uit een bibliotheek waarvoor het bij het publiceren moet worden ingekort, kan het onderdeel tijdens het publiceren worden afgekapt omdat er geen verwijzingen naar zijn vanuit app-code aan de clientzijde. Als gevolg hiervan wordt het onderdeel niet vooraf gerendeerd, waarbij een lege plek in de uitvoer achterblijft. Als dit gebeurt, geeft u de trimmer de instructie om het bibliotheekonderdeel te behouden door een DynamicDependency kenmerk toe te voegen aan een klasse in de app aan de clientzijde. Als u een onderdeel wilt behouden dat wordt aangeroepen SomeLibraryComponentToBePreserved, voegt u het volgende toe aan een onderdeel:

@using System.Diagnostics.CodeAnalysis
@attribute [DynamicDependency(DynamicallyAccessedMemberTypes.All, 
    typeof(SomeLibraryComponentToBePreserved))]

De voorgaande benadering is meestal niet vereist, omdat de app meestal de onderdelen voorafzet (die niet zijn ingekort), die op zijn beurt verwijst naar onderdelen uit bibliotheken (waardoor ze ook niet worden afgekapt). DynamicDependency Gebruik alleen expliciet voor het prerenderen van een bibliotheekonderdeel rechtstreeks wanneer de bibliotheek onderhevig is aan bijsnijden.

Onderdelen weergeven in een pagina of weergave met een CSS-selector

Voeg na het configureren van de oplossing, inclusief de aanvullende configuratie, hoofdonderdelen toe aan het Client project van een gehoste Blazor WebAssembly oplossing in het Program.cs bestand. In het volgende voorbeeld wordt het Counter onderdeel gedeclareerd als een hoofdonderdeel met een CSS-selector die het element selecteert met het id element dat overeenkomt counter-component. In het volgende voorbeeld is Clientde naamruimte van het BlazorHosted.Client project.

In het bestand Program.cs van het project Client, voeg de namespace voor de Razor-componenten toe aan het begin van het bestand.

using BlazorHosted.Client.Pages;

Nadat het builder onderdeel is gemaakt in Program.cs, voegt u het Counter onderdeel toe als basiscomponent.

builder.RootComponents.Add<Counter>("#counter-component");

In het volgende Razor paginavoorbeeld wordt het Counter onderdeel weergegeven op een pagina. Als u het onderdeel interactief wilt maken, wordt het Blazor WebAssembly script opgenomen in de weergavesectie van de pagina.

In het Server project: Pages/RazorPagesCounter2.cshtml

@page

<div id="counter-component">Loading...</div>

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Voer het Server project uit. Navigeer naar de Razor pagina op /razorpagescounter2. Het vooraf gegenereerde Counter onderdeel wordt ingesloten in de pagina.

Mogelijk is er extra werk vereist, afhankelijk van de statische resources die onderdelen gebruiken en hoe indelingspagina's in een app worden ingedeeld. Scripts worden doorgaans toegevoegd aan de rendersectie van een pagina of weergave Scripts en stylesheets worden toegevoegd aan de inhoud van het <head> element van de indeling.

Opmerking

In het voorgaande voorbeeld doet een JSException zich voor indien een Blazor WebAssembly-app vooraf wordt gerenderd en geïntegreerd in een Razor Pages- of MVC-app gelijktijdig met gebruik van een CSS-selector. Als u naar een van de onderdelen van het Client project Razor navigeert of naar een pagina of weergave van het Server met een ingesloten onderdeel navigeert, wordt een of meer JSExceptiononderdelen gegenereerd.

Dit is normaal gedrag omdat het prerenderen en integreren van een Blazor WebAssembly app met routeerbare Razor onderdelen niet compatibel is met het gebruik van CSS-selectors.

Als u met de voorbeelden in de voorgaande secties hebt gewerkt en alleen de CSS-selector in uw voorbeeld-app wilt zien, markeert u de specificatie van het App hoofdonderdeel van het Client projectbestand Program.cs :

- builder.RootComponents.Add<App>("#app");
+ //builder.RootComponents.Add<App>("#app");

Navigeer naar de pagina of weergave met het ingesloten Razor onderdeel dat gebruikmaakt van een CSS-selector (bijvoorbeeld /razorpagescounter2 van het vorige voorbeeld). De pagina of weergave wordt geladen met het ingesloten onderdeel en het ingesloten onderdeel werkt zoals verwacht.

Voorgeconfigureerde status behouden

Zonder dat de vooraf gegenereerde status behouden blijft, gaat de status die tijdens het prerenderen wordt gebruikt verloren en moet deze opnieuw worden gemaakt wanneer de app volledig is geladen. Als een toestand asynchroon is ingesteld, kan de gebruikersinterface flikkeren doordat de vooraf gerenderde gebruikersinterface wordt vervangen door tijdelijke aanduidingen en vervolgens weer volledig wordt weergegeven.

Om deze problemen op te lossen, biedt Blazor ondersteuning voor het behouden van de status op een voorgerenderde pagina met behulp van de Taghelper voor het bewaren van status van componenten. Voeg de tag van de Tag Helper toe, <persist-component-state /> in de afsluitende </body> tag.

Pages/_Layout.cshtml:

<body>
    ...

    <persist-component-state />
</body>

Bepaal welke status moet worden behouden met behulp van de PersistentComponentState service. PersistentComponentState.RegisterOnPersisting registreert een callback om de onderdeelstatus te behouden voordat de app wordt onderbroken. De status wordt opgehaald wanneer de toepassing wordt hervat. Maak de aanroep aan het einde van de initialisatiecode om tijdens het afsluiten van de app een potentiële raceconditie te voorkomen.

Het volgende voorbeeld is een bijgewerkte versie van het FetchData onderdeel in een gehoste Blazor WebAssembly app op basis van de Blazor projectsjabloon. Het WeatherForecastPreserveState onderdeel blijft de weersvoorspellingsstatus behouden tijdens het prerenderen en haalt vervolgens de status op om het onderdeel te initialiseren. De Helper voor persistente onderdeelstatustags blijft de status van het onderdeel behouden na alle aanroepen van onderdelen.

Pages/WeatherForecastPreserveState.razor:

@page "/weather-forecast-preserve-state"
@implements IDisposable
@using BlazorSample.Shared
@inject IWeatherForecastService WeatherForecastService
@inject PersistentComponentState ApplicationState

<PageTitle>Weather Forecast</PageTitle>

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <table class="table">
        <thead>
            <tr>
                <th>Date</th>
                <th>Temp. (C)</th>
                <th>Temp. (F)</th>
                <th>Summary</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var forecast in forecasts)
            {
                <tr>
                    <td>@forecast.Date.ToShortDateString()</td>
                    <td>@forecast.TemperatureC</td>
                    <td>@forecast.TemperatureF</td>
                    <td>@forecast.Summary</td>
                </tr>
            }
        </tbody>
    </table>
}

@code {
    private WeatherForecast[] forecasts = Array.Empty<WeatherForecast>();
    private PersistingComponentStateSubscription persistingSubscription;

    protected override async Task OnInitializedAsync()
    {
        if (!ApplicationState.TryTakeFromJson<WeatherForecast[]>(
            nameof(forecasts), out var restored))
        {
            forecasts = 
                await WeatherForecastService.GetForecastAsync(DateTime.Now);
        }
        else
        {
            forecasts = restored!;
        }

        // Call at the end to avoid a potential race condition at app shutdown
        persistingSubscription = ApplicationState.RegisterOnPersisting(PersistData);
    }

    private Task PersistData()
    {
        ApplicationState.PersistAsJson(nameof(forecasts), forecasts);

        return Task.CompletedTask;
    }

    void IDisposable.Dispose()
    {
        persistingSubscription.Dispose();
    }
}

Door onderdelen te initialiseren met dezelfde status die tijdens het prerenderen wordt gebruikt, worden dure initialisatiestappen slechts één keer uitgevoerd. De gerenderde gebruikersinterface komt ook overeen met de vooraf gegenereerde gebruikersinterface, dus er treedt geen flikkering op in de browser.

De persistente vooraf gegenereerde status wordt overgebracht naar de client, waar deze wordt gebruikt om de status van het onderdeel te herstellen. Voor prerendering in een gehoste Blazor WebAssembly app worden de gegevens blootgesteld aan de browser en mogen ze geen gevoelige, persoonlijke gegevens bevatten.

Aanvullende Blazor WebAssembly informatiebronnen

Prerendering kan seo (Search Engine Optimization) verbeteren door inhoud weer te geven voor het eerste HTTP-antwoord dat zoekmachines kunnen gebruiken om de paginarang te berekenen.

Oplossingsconfiguratie

Prerenderingsconfiguratie

Prerendering instellen voor een gehoste Blazor WebAssembly app:

  1. Blazor WebAssembly De app hosten in een ASP.NET Core-app. Een zelfstandige Blazor WebAssembly app kan worden toegevoegd aan een ASP.NET Core-oplossing of u kunt een gehoste Blazor WebAssembly app gebruiken die is gemaakt op basis van de Blazor WebAssembly projectsjabloon met de gehoste optie:

    • Visual Studio: Schakel in het dialoogvenster Aanvullende informatie het selectievakje ASP.NET Core Hosted in bij het maken van de Blazor WebAssembly app. In de voorbeelden van dit artikel heeft de oplossing de naam BlazorHosted.
    • Visual Studio Code/.NET CLI-opdrachtshell: dotnet new blazorwasm -ho (gebruik de -ho|--hosted optie). Gebruik de -o|--output {LOCATION} optie om een map voor de oplossing te maken en stel de projectnaamruimten van de oplossing in. In de voorbeelden van dit artikel heeft de oplossing de naam BlazorHosted (dotnet new blazorwasm -ho -o BlazorHosted).

    Voor de voorbeelden in dit artikel is de naamruimte van het clientproject BlazorHosted.Client, en de naamruimte van het serverproject is BlazorHosted.Server.

  2. Verwijder het wwwroot/index.html bestand uit het Blazor WebAssemblyClient project.

  3. Verwijder in het Client project de volgende regel inProgram.cs:

    - builder.RootComponents.Add<App>("#app");
    
  4. Voeg een Pages/_Host.cshtml bestand toe aan de Server map van het Pages project. U kunt een _Host.cshtml bestand ophalen uit een project dat is gemaakt op basis van de Blazor Server sjabloon met de dotnet new blazorserver -o BlazorServer opdracht in een opdrachtshell (met de -o BlazorServer optie wordt een map voor het project gemaakt). Nadat u het Pages/_Host.cshtml bestand in het Server project van de gehoste oplossing hebt geplaatst Blazor WebAssembly , moet u de volgende wijzigingen aanbrengen in het bestand:

    • Geef een @using richtlijn op voor het Client project (bijvoorbeeld @using BlazorHosted.Client).

    • Werk de stylesheet-koppelingen bij zodat deze verwijzen naar de stylesheets van het WebAssembly-project. In het volgende voorbeeld is BlazorHosted.Clientde naamruimte van het clientproject:

      - <link href="css/site.css" rel="stylesheet" />
      - <link href="_content/BlazorServer/_framework/scoped.styles.css" rel="stylesheet" />
      + <link href="css/app.css" rel="stylesheet" />
      + <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
      

      Opmerking

      Laat het <link> element staan dat het Bootstrap-opmaakmodel (css/bootstrap/bootstrap.min.css) aanvraagt.

    • Werk de render-mode van de Component Tag Helper bij om de rootcomponent App vooraf te renderen met WebAssemblyPrerendered:

      - <component type="typeof(App)" render-mode="ServerPrerendered" />
      + <component type="typeof(App)" render-mode="WebAssemblyPrerendered" />
      
    • Werk de Blazor scriptbron bij om het client-side Blazor WebAssembly script te gebruiken.

      - <script src="_framework/blazor.server.js"></script>
      + <script src="_framework/blazor.webassembly.js"></script>
      
  5. Wijzig in het Startup.Configure project de fallback van het Server bestand naar de index.html pagina.

    Startup.cs:

    - endpoints.MapFallbackToFile("index.html");
    + endpoints.MapFallbackToPage("/_Host");
    
  6. Als de Client en Server projecten een of meer algemene services gebruiken tijdens het prerendering, moet u rekening houden met de serviceregistraties in een methode die vanuit beide projecten kan worden aangeroepen. Zie ASP.NET Core Blazor dependency injectionvoor meer informatie.

  7. Voer het Server project uit. De gehoste Blazor WebAssembly app wordt vooraf gerenderd door het Server project voor klanten.

Configuratie voor het insluiten van Razor onderdelen in pagina's of weergaven

De volgende secties en voorbeelden in dit artikel voor het insluiten Razor van onderdelen van de client-app Blazor WebAssembly in pagina's of weergaven van de server-app vereisen extra configuratie.

Gebruik een standaard Razor Pagina's- of MVC-lay-outbestand in het Server project. Het Server project moet de volgende bestanden en mappen hebben.

Razor Bladzijden:

  • Pages/Shared/_Layout.cshtml
  • Pages/_ViewImports.cshtml
  • Pages/_ViewStart.cshtml

MVC:

  • Views/Shared/_Layout.cshtml
  • Views/_ViewImports.cshtml
  • Views/_ViewStart.cshtml

Haal de voorgaande bestanden op uit een app die is gemaakt op basis van de Razor projectsjabloon Pages of MVC. Zie Zelfstudie: Aan de slag met Razor Pagina's in ASP.NET Core of Aan de slag met ASP.NET Core MVC voor meer informatie.

Werk de naamruimten in het geïmporteerde _ViewImports.cshtml bestand bij zodat deze overeenkomen met de naamruimten die worden gebruikt door het Server project dat de bestanden ontvangt.

Werk het geïmporteerde indelingsbestand (_Layout.cshtml) bij om de stijlen van het Client project op te nemen. In het volgende voorbeeld is Clientde naamruimte van het BlazorHosted.Client project. Het <title> element kan tegelijkertijd worden bijgewerkt.

Pages/Shared/_Layout.cshtml (Razor Pagina's) Of Views/Shared/_Layout.cshtml (MVC):

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-   <title>@ViewData["Title"] - DonorProject</title>
+   <title>@ViewData["Title"] - BlazorHosted</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
+   <link href="css/app.css" rel="stylesheet" />
+   <link href="BlazorHosted.Client.styles.css" rel="stylesheet" />
</head>

De geïmporteerde indeling bevat Home en Privacy navigatiekoppelingen. Als u de Home koppeling naar de gehoste Blazor WebAssembly app wilt laten verwijzen, wijzigt u de hyperlink:

- <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

In een MVC-indelingsbestand:

- <a class="nav-link text-dark" asp-area="" asp-controller="Home" 
-     asp-action="Index">Home</a>
+ <a class="nav-link text-dark" href="/">Home</a>

Als u de Privacy koppeling naar een privacypagina wilt leiden, voegt u een privacypagina toe aan het Server project.

Pages/Privacy.cshtml in het Server project:

@page
@model BlazorHosted.Server.Pages.PrivacyModel
@{
}

<h1>Privacy Policy</h1>

Als een privacyweergave op basis van MVC de voorkeur heeft, maakt u een privacyweergave in het Server project.

View/Home/Privacy.cshtml:

@{
    ViewData["Title"] = "Privacy Policy";
}

<h1>@ViewData["Title"]</h1>

Retourneer de weergave in de Home controller.

Controllers/HomeController.cs:

public IActionResult Privacy()
{
    return View();
}

Importeer statische assets naar het Server project vanuit de wwwroot map van het donorproject.

  • wwwroot/css map en inhoud
  • wwwroot/js map en inhoud
  • wwwroot/lib map en inhoud

Als het donorproject wordt gemaakt op basis van een ASP.NET Core-projectsjabloon en de bestanden niet worden gewijzigd, kunt u de hele wwwroot map van het donorproject naar het Server project kopiëren en het favicon pictogrambestand verwijderen.

Waarschuwing

Vermijd het plaatsen van de statische asset zowel in de Client map als in de Serverwwwroot mappen. Als hetzelfde bestand in beide mappen aanwezig is, wordt er een uitzondering gegenereerd omdat de statische asset in elke map hetzelfde webhoofdpad deelt. Host daarom een statische asset in een van beide wwwroot mappen, niet beide.

Onderdelen weergeven in een pagina of weergave met de Helper voor onderdeeltags

Nadat u de oplossing hebt geconfigureerd, inclusief de aanvullende configuratie, ondersteunt de Tag Helper voor onderdelen twee rendermodi voor het weergeven van een onderdeel vanuit een Blazor WebAssembly app in een pagina of weergave:

In het volgende Razor paginavoorbeeld wordt het Counter onderdeel weergegeven op een pagina. Als u het onderdeel interactief wilt maken, wordt het Blazor WebAssembly script opgenomen in de weergavesectie van de pagina. Als u wilt voorkomen dat u de volledige naamruimte voor het Counter onderdeel gebruikt met de Component Tag Helper ({ASSEMBLY NAME}.Pages.Counter), voegt u een @using instructie toe voor de naamruimte van Pages het clientproject. In het volgende voorbeeld is Clientde naamruimte van het BlazorHosted.Client project.

In het Server project: Pages/RazorPagesCounter1.cshtml

@page
@using BlazorHosted.Client.Pages

<component type="typeof(Counter)" render-mode="WebAssemblyPrerendered" />

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Voer het Server project uit. Navigeer naar de Razor pagina op /razorpagescounter1. Het vooraf gegenereerde Counter onderdeel wordt ingesloten in de pagina.

RenderMode hiermee configureert u of het onderdeel:

  • Wordt vooraf in de pagina weergegeven.
  • Wordt weergegeven als statische HTML op de pagina of als deze de benodigde informatie bevat voor het opstarten van een Blazor app van de gebruikersagent.

Zie Component RenderMode voor meer informatie over de Component Tag Helper, inclusief het doorgeven van parameters en configuratie.

Mogelijk is er extra werk vereist, afhankelijk van de statische resources die onderdelen gebruiken en hoe indelingspagina's in een app worden ingedeeld. Scripts worden doorgaans toegevoegd aan de rendersectie van een pagina of weergave Scripts en stylesheets worden toegevoegd aan de inhoud van het <head> element van de indeling.

Onderdelen weergeven in een pagina of weergave met een CSS-selector

Voeg na het configureren van de oplossing, inclusief de aanvullende configuratie, hoofdonderdelen toe aan het Client project van een gehoste Blazor WebAssembly oplossing in Program.cs. In het volgende voorbeeld wordt het Counter onderdeel gedeclareerd als een hoofdonderdeel met een CSS-selector die het element selecteert met het id element dat overeenkomt counter-component. In het volgende voorbeeld is Clientde naamruimte van het BlazorHosted.Client project.

Voeg in het Program.cs-project de naamruimte voor de Client-onderdelen van het project toe aan het begin van het bestand:

using BlazorHosted.Client.Pages;

Nadat het builder onderdeel is gemaakt in Program.cs, voegt u het Counter onderdeel toe als basiscomponent.

builder.RootComponents.Add<Counter>("#counter-component");

In het volgende Razor paginavoorbeeld wordt het Counter onderdeel weergegeven op een pagina. Als u het onderdeel interactief wilt maken, wordt het Blazor WebAssembly script opgenomen in de weergavesectie van de pagina.

In het Server project: Pages/RazorPagesCounter2.cshtml

@page

<div id="counter-component">Loading...</div>

@section Scripts {
    <script src="_framework/blazor.webassembly.js"></script>
}

Voer het Server project uit. Navigeer naar de Razor pagina op /razorpagescounter2. Het vooraf gegenereerde Counter onderdeel wordt ingesloten in de pagina.

Mogelijk is er extra werk vereist, afhankelijk van de statische resources die onderdelen gebruiken en hoe indelingspagina's in een app worden ingedeeld. Scripts worden doorgaans toegevoegd aan de rendersectie van een pagina of weergave Scripts en stylesheets worden toegevoegd aan de inhoud van het <head> element van de indeling.

Opmerking

In het voorgaande voorbeeld zal een JSException worden gegenereerd als een Blazor WebAssembly app vooraf gerenderd en geïntegreerd wordt in een Razor Pages- of MVC-app gelijktijdig met een CSS-selector. Als u naar een van de onderdelen van het Client project Razor navigeert, wordt de volgende uitzondering gegenereerd:

Microsoft.JSInterop.JSException: Kan geen elementen vinden die overeenkomen met de selector '#counter-component'.

Dit is normaal gedrag omdat het prerenderen en integreren van een Blazor WebAssembly app met routeerbare Razor onderdelen niet compatibel is met het gebruik van CSS-selectors.

Aanvullende Blazor WebAssembly informatiebronnen

Het integreren van Razor onderdelen in Razor Pages- of MVC-apps in een gehoste Blazor WebAssemblyoplossing wordt ondersteund in ASP.NET Core in .NET 5 of hoger. Selecteer een .NET 5- of nieuwere versie van dit artikel.