Delen via


richtlijnen voor ASP.NET Core-BlazorSignalR

Notitie

Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikelvoor de huidige release.

Waarschuwing

Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie de .NET- en .NET Core-ondersteuningsbeleidvoor meer informatie. Zie de .NET 9-versie van dit artikelvoor de huidige release.

Belangrijk

Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.

Zie de .NET 9-versie van dit artikelvoor de huidige release.

In dit artikel wordt uitgelegd hoe u SignalR verbindingen in Blazor-apps configureert en beheert.

Zie de onderwerpen in het Overzicht van ASP.NET Core SignalR gebied van de documentatie voor algemene richtlijnen over ASP.NET Core SignalR-configuratie, met name ASP.NET Core SignalR-configuratie.

Apps aan de serverzijde gebruiken ASP.NET Core SignalR om te communiceren met de browser. SignalR's hosting- en schaalvoorwaarden zijn van toepassing op server-side apps.

Blazor werkt het beste bij het gebruik van WebSockets als het SignalR transport vanwege een lagere latentie, betrouwbaarheid en beveiliging. Long Polling wordt gebruikt door SignalR wanneer WebSockets niet beschikbaar is of wanneer de app expliciet is geconfigureerd voor het gebruik van Long Polling.

Azure SignalR Service met stateful opnieuw verbinding maken

De Azure SignalR-service met SDK v1.26.1 of hoger ondersteunt SignalR opnieuw verbinden met toestandsbehoud (WithStatefulReconnect).

WebSocket-compressie voor interactieve serveronderdelen

Interactieve serveronderdelen zijn standaard:

  • Schakel compressie in voor WebSocket-verbindingen. DisableWebSocketCompression (standaard: false) bepaalt WebSocket-compressie.

  • Een frame-ancestorsContent Security Policy (CSP)-instructie aannemen die is ingesteld op 'self', waardoor de app alleen kan worden ingesloten in een <iframe> van de oorsprong van waaruit de app wordt geleverd wanneer er een configuratie voor de WebSocket-context wordt geboden of wanneer compressie is ingeschakeld. ContentSecurityFrameAncestorPolicy beheert de frame-ancestors CSP.

De frame-ancestors CSP kan handmatig worden verwijderd door de waarde van ContentSecurityFrameAncestorsPolicy in te stellen op null, omdat u de CSP mogelijk op een gecentraliseerde manier wiltconfigureren. Wanneer de frame-ancestors CSP op een gecentraliseerde manier wordt beheerd, moet u ervoor zorgen dat een beleid wordt toegepast wanneer het eerste document wordt weergegeven. We raden u niet aan het beleid volledig te verwijderen, omdat de app mogelijk kwetsbaar is voor aanvallen.

Gebruik ConfigureWebSocketAcceptContext om de WebSocketAcceptContext te configureren voor de websocket-verbindingen die door de serveronderdelen worden gebruikt. Standaard wordt een beleid dat compressie mogelijk maakt en een CSP instelt voor de framevoorouders die in ContentSecurityFrameAncestorsPolicy zijn gedefinieerd, toegepast.

Gebruiksvoorbeelden:

Schakel compressie uit door DisableWebSocketCompression in te stellen op true, waardoor het beveiligingsprobleem van de app wordt verminderd om aan te vallen, maar dit kan leiden tot verminderde prestaties:

builder.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode(o => o.DisableWebSocketCompression = true)

Wanneer compressie is ingeschakeld, configureert u een strengere frame-ancestors CSP met een waarde van 'none' (enkele aanhalingstekens vereist), waarmee WebSocket-compressie mogelijk is, maar voorkomt u dat browsers de app insluiten in een <iframe>:

builder.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = "'none'")

Wanneer compressie is ingeschakeld, verwijdert u de frame-ancestors CSP door ContentSecurityFrameAncestorsPolicy in te stellen op null. Dit scenario wordt alleen aanbevolen voor apps die de CSP op een gecentraliseerde manier instellen:

builder.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy = null)

Belangrijk

Browsers passen CSP-richtlijnen van meerdere CSP-headers toe met de striktste beleidswaarde. Daarom kan een ontwikkelaar geen zwakkere frame-ancestors beleid toevoegen dan 'self' opzettelijk of per ongeluk.

Enkele aanhalingstekens zijn vereist voor de tekenreekswaarde die wordt doorgegeven aan ContentSecurityFrameAncestorsPolicy:

Niet-ondersteunde waarden:none, self

✔️ Ondersteunde waarden:'none', 'self'

Aanvullende opties zijn onder andere het opgeven van een of meer hostbronnen en schemabronnen.

Zie Richtlijnen voor bedreigingsbeperking voor ASP.NET Core Blazor interactieve rendering aan de serverzijdevoor gevolgen voor de beveiliging. Zie CSP: frame-ancestors (MDN-documentatie)voor meer informatie over de frame-ancestors-instructie.

Antwoordcompressie uitschakelen voor hot-reload

Schakel Middleware voor antwoordcompressie uit wanneer u Hot Reloadgebruikt in de Development-omgeving. Of de standaardcode van een projectsjabloon al dan niet wordt gebruikt, roep altijd UseResponseCompression eerst aan in de aanvraagverwerkingspijplijn.

In het bestand Program:

if (!app.Environment.IsDevelopment())
{
    app.UseResponseCompression();
}

SignalR cross-origin-onderhandeling aan de clientzijde voor verificatie

In deze sectie wordt uitgelegd hoe u de onderliggende client van SignalRconfigureert voor het verzenden van referenties, zoals cookies of HTTP-verificatieheaders.

Gebruik SetBrowserRequestCredentials om Include in te stellen bij fetch aanvragen van andere bronnen.

IncludeRequestCredentialsMessageHandler.cs:

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Http;

public class IncludeRequestCredentialsMessageHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
        return base.SendAsync(request, cancellationToken);
    }
}

Wanneer er een hubverbinding is gemaakt, wijst u de HttpMessageHandler toe aan de optie HttpMessageHandlerFactory:

private HubConnectionBuilder? hubConnection;

...

hubConnection = new HubConnectionBuilder()
    .WithUrl(new Uri(Navigation.ToAbsoluteUri("/chathub")), options =>
    {
        options.HttpMessageHandlerFactory = innerHandler => 
            new IncludeRequestCredentialsMessageHandler { InnerHandler = innerHandler };
    }).Build();

In het voorgaande voorbeeld wordt de hubverbindings-URL geconfigureerd naar het absolute URI-adres op /chathub. De URI kan ook worden ingesteld via een tekenreeks, bijvoorbeeld https://signalr.example.comof via configuratie. Navigation is een geïnjecteerde NavigationManager.

Zie ASP.NET Core SignalR-configuratievoor meer informatie.

Rendering aan clientzijde

Als prerendering is geconfigureerd, wordt prerendering uitgevoerd voordat de clientverbinding met de server tot stand komt. Zie Prerender ASP.NET Core Razor-onderdelenvoor meer informatie.

Als prerendering is geconfigureerd, vindt prerendering plaats voordat de clientverbinding met de server tot stand is gebracht. Zie de volgende artikelen voor meer informatie:

Vooraf weergegeven statusgrootte en SignalR limiet voor berichtgrootte

Een grote vooraf berekende statusgrootte kan groter zijn dan de berichtgrootte limiet van het circuit van BlazorSignalR, wat resulteert in het volgende:

  • Het SignalR-circuit initialiseert niet vanwege een fout op de client: Circuit host not initialized.
  • De gebruikersinterface voor opnieuw verbinden op de client wordt weergegeven wanneer het circuit mislukt. Herstel is niet mogelijk.

Gebruik van de volgende methoden om het probleem op te lossen:

  • Verminder de hoeveelheid gegevens die u in de vooraf weergegeven status plaatst.
  • Verhoog de limiet voor SignalR berichtgrootte. WAARSCHUWING: Als u de limiet verhoogt, kan het risico op DoS-aanvallen (Denial of Service) toenemen.

Extra hulpmiddelen aan klantzijde

Sessieaffiniteit (stickysessies) gebruiken voor serverside webfarm-hosting

Wanneer er meer dan één backendserver in gebruik is, moet de app sessieaffiniteit implementeren, ook wel plaksessiesgenoemd. Sessieaffiniteit zorgt ervoor dat het circuit van een client opnieuw verbinding maakt met dezelfde server als de verbinding wordt verbroken. Dit is belangrijk omdat de clientstatus alleen wordt bewaard in het geheugen van de server waarop het circuit van de client voor het eerst is ingesteld.

De volgende fout wordt gegenereerd door een app die sessieaffiniteit niet heeft ingeschakeld in een webfarm:

Uncaught (in promise) Error: Invocation canceled due to the underlying connection being closed.

Zie Host en implementeer ASP.NET Core-apps Blazor-appsvoor meer informatie over sessieaffiniteit met Azure App Service-hosting.

Azure SignalR Dienst

De optionele Azure SignalR Service- werkt in combinatie met de SignalR hub van de app voor het omhoog schalen van een app aan de serverzijde naar een groot aantal gelijktijdige verbindingen. Bovendien helpen het wereldwijde bereik en de hoogwaardige prestatiedatacenters van de service aanzienlijk om de latentie te verminderen vanwege geografische factoren.

De service is niet vereist voor Blazor apps die worden gehost in Azure App Service of Azure Container Apps, maar kan nuttig zijn in andere hostingomgevingen:

  • Om het uitschalen van verbindingen te vergemakkelijken.
  • Globale distributie beheren.

Voor meer informatie, zie Host en implementeer ASP.NET Core-Blazor-apps.

Opties voor circuithandler aan de serverzijde

Configureer het circuit met CircuitOptions. Standaardwaarden weergeven in de verwijzingsbron.

Notitie

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-vertakkingen of tags vervolgkeuzelijst. Zie Een versietag selecteren van ASP.NET Core-broncode (dotnet/AspNetCore.Docs #26205)voor meer informatie.

Lees of stel de opties in het Program-bestand in met een optiedelegee voor AddInteractiveServerComponents. De tijdelijke aanduiding {OPTION} vertegenwoordigt de optie en de tijdelijke aanduiding {VALUE} is de waarde.

In het bestand Program:

builder.Services.AddRazorComponents().AddInteractiveServerComponents(options =>
{
    options.{OPTION} = {VALUE};
});

Lees of stel de opties in het Program-bestand in met een optiedelegaat voor AddServerSideBlazor. De tijdelijke aanduiding {OPTION} vertegenwoordigt de optie en de tijdelijke aanduiding {VALUE} is de waarde.

In het bestand Program:

builder.Services.AddServerSideBlazor(options =>
{
    options.{OPTION} = {VALUE};
});

Lees of stel de opties in Startup.ConfigureServices in met een gedelegeerde opties voor AddServerSideBlazor. De tijdelijke aanduiding {OPTION} vertegenwoordigt de optie en de tijdelijke aanduiding {VALUE} is de waarde.

In Startup.ConfigureServices van Startup.cs:

services.AddServerSideBlazor(options =>
{
    options.{OPTION} = {VALUE};
});

Als u de HubConnectionContextwilt configureren, gebruikt u HubConnectionContextOptions met AddHubOptions. Bekijk de standaardinstellingen voor de hubverbindingscontextopties in referentiebron. Zie ASP.NET Core SignalR configurationvoor beschrijvingen van opties in de SignalR documentatie. De tijdelijke aanduiding {OPTION} vertegenwoordigt de optie en de tijdelijke aanduiding {VALUE} is de waarde.

Notitie

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 vervolgkeuzelijst Switch branches of tags. Zie Een versietag selecteren van ASP.NET Core-broncode (dotnet/AspNetCore.Docs #26205)voor meer informatie.

In het bestand Program:

builder.Services.AddRazorComponents().AddInteractiveServerComponents().AddHubOptions(options =>
{
    options.{OPTION} = {VALUE};
});

In het bestand Program:

builder.Services.AddServerSideBlazor().AddHubOptions(options =>
{
    options.{OPTION} = {VALUE};
});

In Startup.ConfigureServices van Startup.cs:

services.AddServerSideBlazor().AddHubOptions(options =>
{
    options.{OPTION} = {VALUE};
});

Waarschuwing

De standaardwaarde van MaximumReceiveMessageSize is 32 kB. Het verhogen van de waarde kan het risico verhogen van DoS-aanvallen (Denial of Service).

Blazor is afhankelijk van MaximumParallelInvocationsPerClient ingesteld op 1. Dit is de standaardwaarde. Voor meer informatie, zie MaximumParallelInvocationsPerClient > 1, hierdoor wordt het uploaden van bestanden in Blazor Server-modus (dotnet/aspnetcore #53951)onderbroken.

Zie Host en implementeer ASP.NET Core-Blazor-apps aan de serverzijdevoor meer informatie over geheugenbeheer.

Blazor hubopties

Configureer MapBlazorHub opties om HttpConnectionDispatcherOptions van de Blazor hub te beheren. Bekijk de standaardinstellingen voor de dispatcheropties voor hubverbinding in referentiebron . De tijdelijke aanduiding {OPTION} vertegenwoordigt de optie en de tijdelijke aanduiding {VALUE} is de waarde.

Notitie

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 Schakelen tussen branches of tags vervolgkeuzelijst. Zie Een versietag selecteren van ASP.NET Core-broncode (dotnet/AspNetCore.Docs #26205)voor meer informatie.

Plaats de aanroep naar app.MapBlazorHub na de aanroep naar app.MapRazorComponents in het Program-bestand van de app:

app.MapBlazorHub(options =>
{
    options.{OPTION} = {VALUE};
});

Het configureren van de hub die wordt gebruikt door AddInteractiveServerRenderMode met MapBlazorHub mislukt met een fout AmbiguousMatchException.

Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints.

Als tijdelijke oplossing voor het probleem voor apps die gericht zijn op .NET 8, geeft u de aangepaste Blazor hub een hogere prioriteit met behulp van de methode WithOrder:

app.MapBlazorHub(options =>
{
    options.CloseOnAuthenticationExpiration = true;
}).WithOrder(-1);

Zie de volgende bronnen voor meer informatie:

Geef de opties op voor app.MapBlazorHub in het Program-bestand van de app:

app.MapBlazorHub(options =>
{
    options.{OPTION} = {VALUE};
});

Geef de opties op voor app.MapBlazorHub in de routeringsconfiguratie van eindpunten:

app.UseEndpoints(endpoints =>
{
    endpoints.MapBlazorHub(options =>
    {
        options.{OPTION} = {VALUE};
    });
    ...
});

Maximale grootte van het ontvangen van berichten

Deze sectie is alleen van toepassing op projecten die SignalRimplementeren.

De maximale binnenkomende SignalR berichtgrootte die is toegestaan voor hubmethoden, wordt beperkt door de HubOptions.MaximumReceiveMessageSize (standaard: 32 kB). SignalR berichten die groter zijn dan MaximumReceiveMessageSize een fout veroorzaken. Het framework legt geen limiet op voor de grootte van een SignalR bericht van de hub naar een client.

Wanneer SignalR logboekregistratie niet is ingesteld op Foutopsporing of Trace, wordt er alleen een foutbericht weergegeven in de console voor ontwikkelhulpprogramma's van de browser:

Fout: De verbinding is verbroken met de fout 'Fout: Server heeft een fout geretourneerd bij sluiten: Verbinding gesloten met een fout.'

Wanneer SignalR logboekregistratie aan de serverzijde is ingesteld op Foutopsporing of Traceren, wordt aan de serverzijde een InvalidDataException weergegeven voor een fout in de berichtgrootte.

appsettings.Development.json:

{
  "DetailedErrors": true,
  "Logging": {
    "LogLevel": {
      ...
      "Microsoft.AspNetCore.SignalR": "Debug"
    }
  }
}

Fout:

System.IO.InvalidDataException: de maximale berichtgrootte van 32768B is overschreden. De berichtgrootte kan worden geconfigureerd in AddHubOptions.

Een benadering omvat het verhogen van de limiet door MaximumReceiveMessageSize in het Program bestand in te stellen. In het volgende voorbeeld wordt de maximale berichtgrootte ingesteld op 64 kB:

builder.Services.AddRazorComponents().AddInteractiveServerComponents()
    .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);

Het verhogen van de limiet voor de SignalR binnenkomende berichtgrootte komt ten koste van het vereisen van meer serverresources en het verhoogt het risico op DoS-aanvallen (Denial of Service). Daarnaast kan het lezen van een grote hoeveelheid inhoud in het geheugen als tekenreeksen of byte-arrays ook leiden tot toewijzingen die niet goed samenwerken met de garbagecollector, waardoor extra prestatieverlies optreedt.

Een betere optie voor het lezen van grote nettoladingen is het verzenden van de inhoud in kleinere segmenten en het verwerken van de nettolading als een Stream. Dit kan worden gebruikt bij het lezen van grote JavaScript (JS) interop JSON-payloads of als JS interop-gegevens beschikbaar zijn als ruwe bytes. Zie voor een voorbeeld van het verzenden van grote binaire gegevens in server-side-apps die gebruikmaken van technieken die vergelijkbaar zijn met het InputFile onderdeel, de Binair verzenden voorbeeld-app en de BlazorInputLargeTextArea componentvoorbeeld-app.

Notitie

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-vertakkingen of tags vervolgkeuzelijst. Zie Een versietag selecteren van ASP.NET Core-broncode (dotnet/AspNetCore.Docs #26205)voor meer informatie.

Formulieren die grote gegevensladingen via SignalR verwerken, kunnen ook gebruik maken van directe streaming JS interop. Zie .NET-methoden aanroepen vanuit JavaScript-functies in ASP.NET Core Blazorvoor meer informatie. Zie Probleemoplossing voor ASP.NET Core Blazor-formulierenvoor een voorbeeld van formulieren waarbij <textarea> naar de server wordt gestreamd.

Een benadering omvat het verhogen van de limiet door MaximumReceiveMessageSize in het Program bestand in te stellen. In het volgende voorbeeld wordt de maximale berichtgrootte ingesteld op 64 kB:

builder.Services.AddServerSideBlazor()
    .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);

Het verhogen van de limiet voor de SignalR binnenkomende berichtgrootte komt ten koste van het vereisen van meer serverresources en het verhoogt het risico op DoS-aanvallen (Denial of Service). Daarnaast kan het lezen van een grote hoeveelheid inhoud in het geheugen als tekenreeksen of bytematrices ook leiden tot toewijzingen die slecht werken met de garbagecollector, wat resulteert in extra prestatiestraffen.

Een betere optie voor het lezen van grote nettoladingen is het verzenden van de inhoud in kleinere segmenten en het verwerken van de nettolading als een Stream. Dit kan worden gebruikt bij het lezen van grote JavaScript (JS) interop JSON-payloads of als JS interop-gegevens beschikbaar zijn als ruwe bytes. Zie voor een voorbeeld van het verzenden van grote binaire nettoladingen in Blazor Server die gebruikmaken van technieken die vergelijkbaar zijn met het InputFile onderdeel, de binaire indienen-voorbeeldapp en het BlazorInputLargeTextArea componentvoorbeeld.

Notitie

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-vertakkingen of tags vervolgkeuzelijst. Zie Een versietag selecteren van ASP.NET Core-broncode (dotnet/AspNetCore.Docs #26205)voor meer informatie.

Formulieren die grote gegevens via SignalR verwerken, kunnen ook rechtstreeks gebruikmaken van streaming JS interop. Zie .NET-methoden aanroepen vanuit JavaScript-functies in ASP.NET Core Blazorvoor meer informatie. Zie Problemen met ASP.NET Core Blazor-formulierenoplossen voor een voorbeeld van formulieren die <textarea> in een Blazor Server-app worden gestreamd.

Verhoog de limiet door MaximumReceiveMessageSize in Startup.ConfigureServicesin te stellen:

services.AddServerSideBlazor()
    .AddHubOptions(options => options.MaximumReceiveMessageSize = 64 * 1024);

Het verhogen van de limiet voor de SignalR binnenkomende berichtgrootte komt ten koste van het vereisen van meer serverresources en het verhoogt het risico op DoS-aanvallen (Denial of Service). Daarnaast kan het lezen van een grote hoeveelheid inhoud in het geheugen als tekenreeksen of byte-arrays ook leiden tot toewijzingen die slecht werken met de garbagecollector, wat resulteert in extra prestatieverlies.

Houd rekening met de volgende richtlijnen bij het ontwikkelen van code waarmee een grote hoeveelheid gegevens wordt overgedragen:

  • Maak gebruik van de systeemeigen ondersteuning voor streaming JS interop om gegevens over te dragen die groter zijn dan de limiet voor binnenkomende berichten van SignalR:
  • Algemene tips:
    • Wijs geen grote objecten toe in JS- en C#-code.
    • Vrij verbruikt geheugen wanneer het proces is voltooid of geannuleerd.
    • Dwing de volgende aanvullende vereisten af voor beveiligingsdoeleinden:
      • Declareer de maximale bestandsgrootte of gegevensgrootte die kan worden doorgegeven.
      • Declareer de minimale uploadsnelheid van de client naar de server.
    • Nadat de gegevens door de server zijn ontvangen, kunnen de gegevens het volgende zijn:
      • Tijdelijk opgeslagen in een geheugenbuffer totdat alle segmenten worden verzameld.
      • Onmiddellijk verbruikt. De gegevens kunnen bijvoorbeeld direct worden opgeslagen in een database of naar schijf worden geschreven wanneer elk segment wordt ontvangen.
  • Segmenter de gegevens in kleinere delen en verzend de gegevenssegmenten opeenvolgend totdat alle gegevens door de server worden ontvangen.
  • Wijs geen grote objecten toe in JS- en C#-code.
  • Blokkeer de hoofd-UI-thread niet gedurende lange perioden bij het verzenden of ontvangen van gegevens.
  • Vrij verbruikt geheugen wanneer het proces is voltooid of geannuleerd.
  • Dwing de volgende aanvullende vereisten af voor beveiligingsdoeleinden:
    • Declareer de maximale bestandsgrootte of gegevensgrootte die kan worden doorgegeven.
    • Declareer de minimale uploadsnelheid van de client naar de server.
  • Nadat de gegevens door de server zijn ontvangen, kunnen de gegevens het volgende zijn:
    • Tijdelijk opgeslagen in een geheugenbuffer totdat alle segmenten worden verzameld.
    • Onmiddellijk verbruikt. De gegevens kunnen bijvoorbeeld direct worden opgeslagen in een database of naar schijf worden geschreven wanneer elk segment wordt ontvangen.

configuratie van Blazor hub-eindpuntroute aan de serverzijde

Roep in het Program bestand MapBlazorHub aan om de BlazorHub toe te wijzen aan het standaardpad van de app. Het Blazor script (blazor.*.js) verwijst automatisch naar het eindpunt dat is gemaakt door MapBlazorHub.

De verbindingsstatus aan de serverzijde weergeven in de gebruikersinterface

Als de client een verbroken verbinding met de server detecteert, wordt er een standaardgebruikersinterface weergegeven aan de gebruiker terwijl de client probeert opnieuw verbinding te maken:

de standaardinterface voor opnieuw verbinden.

de standaardinterface voor opnieuw verbinden.

Als het opnieuw verbinden mislukt, krijgt de gebruiker de opdracht om de pagina opnieuw te proberen of opnieuw te laden:

De standaard-

de standaard herstelinterface.

Als opnieuw verbinding wordt gemaakt, gaat de gebruikersstatus vaak verloren. Aangepaste code kan worden toegevoegd aan elk onderdeel om de gebruikersstatus op te slaan en opnieuw te laden tijdens verbindingsfouten. Zie ASP.NET Core Blazor state managementvoor meer informatie.

Als u de gebruikersinterface wilt aanpassen, definieert u één element met een id van components-reconnect-modal in de inhoud van het <body> element. In het volgende voorbeeld wordt het element in het App-onderdeel weergegeven.

App.razor:

Als u de gebruikersinterface wilt aanpassen, definieert u één element met een id van components-reconnect-modal in de inhoud van het <body> element. In het volgende voorbeeld wordt het element op de hostpagina geplaatst.

Pages/_Host.cshtml:

Als u de gebruikersinterface wilt aanpassen, definieert u één element met een id van components-reconnect-modal in de inhoud van het <body> element. In het volgende voorbeeld wordt het element op de indelingspagina geplaatst.

Pages/_Layout.cshtml:

Als u de gebruikersinterface wilt aanpassen, definieert u één element met een id van components-reconnect-modal in de inhoud van het <body> element. In het volgende voorbeeld wordt het element op de hostpagina geplaatst.

Pages/_Host.cshtml:

<div id="components-reconnect-modal">
    Connection lost.<br>Attempting to reconnect...
</div>

Notitie

Als meer dan één element met een id van components-reconnect-modal door de app wordt weergegeven, ontvangt alleen het eerste gerenderde element CSS-klassewijzigingen om het element weer te geven of te verbergen.

Voeg de volgende CSS-stijlen toe aan het opmaakmodel van de site.

wwwroot/app.css:

wwwroot/css/site.css:

#components-reconnect-modal {
    display: none;
}

#components-reconnect-modal.components-reconnect-show, 
#components-reconnect-modal.components-reconnect-failed, 
#components-reconnect-modal.components-reconnect-rejected {
    display: block;
    background-color: white;
    padding: 2rem;
    border-radius: 0.5rem;
    text-align: center;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    margin: 50px 50px;
    position: fixed;
    top: 0;
    z-index: 10001;
}

In de volgende tabel worden de CSS-klassen beschreven die zijn toegepast op het components-reconnect-modal-element door het Blazor framework.

CSS-klasse Geeft...
components-reconnect-show Een verbroken verbinding. De client probeert opnieuw verbinding te maken. Toon het modale venster.
components-reconnect-hide Er wordt een actieve verbinding tot stand gebracht met de server. Verberg de modal.
components-reconnect-failed Opnieuw verbinding maken is mislukt, waarschijnlijk vanwege een netwerkfout. Als u opnieuw verbinding wilt maken, roept u window.Blazor.reconnect() aan in JavaScript.
components-reconnect-rejected Opnieuw verbinden geweigerd. De server is bereikt, maar de verbinding is geweigerd en de status van de gebruiker op de server gaat verloren. Als u de app opnieuw wilt laden, roept u location.reload() aan in JavaScript. Deze verbindingsstatus kan het volgende tot gevolg hebben:
  • Er treedt een crash op in het circuit aan de serverzijde.
  • De client is lang genoeg losgekoppeld zodat de server de gebruikersstatus verliest. Instanties van de onderdelen van de gebruiker worden verwijderd.
  • De server wordt opnieuw opgestart of het werkproces van de app wordt gerecycled.

Pas de vertraging aan voordat de gebruikersinterface voor opnieuw verbinden wordt weergegeven door de eigenschap transition-delay in de CSS van de site in te stellen voor het modale element. In het volgende voorbeeld wordt de overgangsvertraging van 500 ms (standaard) ingesteld op 1000 ms (1 seconde).

wwwroot/app.css:

wwwroot/css/site.css:

#components-reconnect-modal {
    transition: visibility 0s linear 1000ms;
}

Als u de huidige poging om opnieuw verbinding te maken wilt weergeven, definieert u een element met een id van components-reconnect-current-attempt. Als u het maximum aantal nieuwe pogingen voor opnieuw verbinden wilt weergeven, definieert u een element met een id van components-reconnect-max-retries. In het volgende voorbeeld worden deze elementen geplaatst in een modaal element voor een poging tot opnieuw verbinden, volgend op het vorige voorbeeld.

<div id="components-reconnect-modal">
    There was a problem with the connection!
    (Current reconnect attempt: 
    <span id="components-reconnect-current-attempt"></span> /
    <span id="components-reconnect-max-retries"></span>)
</div>

Wanneer de aangepaste modaal voor opnieuw verbinden verschijnt, bevat deze de volgende inhoud met een teller voor pogingen tot opnieuw verbinden:

Er is een probleem met de verbinding! (Huidige poging om opnieuw verbinding te maken: 1/8)

Rendering aan serverzijde

Onderdelen worden standaard voorgerenderd op de server voordat de verbinding van de client met de server tot stand is gebracht. Zie Prerender ASP.NET Core Razor-onderdelenvoor meer informatie.

Componenten worden standaard op de server voorgerenderd voordat de clientverbinding met de server is tot stand gebracht. Zie Component Tag Helper in ASP.NET Corevoor meer informatie.

Activiteit van circuit aan serverzijde bewaken

Bewaak de activiteit van het binnenkomende circuit met behulp van de methode CreateInboundActivityHandler op CircuitHandler. Inkomende circuitactiviteit is elke activiteit die vanuit de browser naar de server wordt verzonden, zoals UI-gebeurtenissen of JavaScript-to-.NET interop-aanroepen.

U kunt bijvoorbeeld een circuitactiviteitshandler gebruiken om te detecteren of de client niet actief is en de circuit-id (Circuit.Id) te registreren:

using Microsoft.AspNetCore.Components.Server.Circuits;
using Microsoft.Extensions.Options;
using Timer = System.Timers.Timer;

public sealed class IdleCircuitHandler : CircuitHandler, IDisposable
{
    private Circuit? currentCircuit;
    private readonly ILogger logger;
    private readonly Timer timer;

    public IdleCircuitHandler(ILogger<IdleCircuitHandler> logger, 
        IOptions<IdleCircuitOptions> options)
    {
        timer = new Timer
        {
            Interval = options.Value.IdleTimeout.TotalMilliseconds,
            AutoReset = false
        };

        timer.Elapsed += CircuitIdle;
        this.logger = logger;
    }

    private void CircuitIdle(object? sender, System.Timers.ElapsedEventArgs e)
    {
        logger.LogInformation("{CircuitId} is idle", currentCircuit?.Id);
    }

    public override Task OnCircuitOpenedAsync(Circuit circuit, 
        CancellationToken cancellationToken)
    {
        currentCircuit = circuit;

        return Task.CompletedTask;
    }

    public override Func<CircuitInboundActivityContext, Task> CreateInboundActivityHandler(
        Func<CircuitInboundActivityContext, Task> next)
    {
        return context =>
        {
            timer.Stop();
            timer.Start();

            return next(context);
        };
    }

    public void Dispose() => timer.Dispose();
}

public class IdleCircuitOptions
{
    public TimeSpan IdleTimeout { get; set; } = TimeSpan.FromMinutes(5);
}

public static class IdleCircuitHandlerServiceCollectionExtensions
{
    public static IServiceCollection AddIdleCircuitHandler(
        this IServiceCollection services, 
        Action<IdleCircuitOptions> configureOptions)
    {
        services.Configure(configureOptions);
        services.AddIdleCircuitHandler();

        return services;
    }

    public static IServiceCollection AddIdleCircuitHandler(
        this IServiceCollection services)
    {
        services.AddScoped<CircuitHandler, IdleCircuitHandler>();

        return services;
    }
}

Registreer de service in het Program-bestand. In het volgende voorbeeld wordt de standaard time-out voor inactiviteit van vijf minuten tot vijf seconden geconfigureerd om de voorgaande IdleCircuitHandler-implementatie te testen:

builder.Services.AddIdleCircuitHandler(options => 
    options.IdleTimeout = TimeSpan.FromSeconds(5));

Circuitactiviteitenhandlers bieden ook een benadering voor toegang tot omvangsgebonden Blazor-services van andere niet-Blazor afhankelijkheidsinjectieomvangen (DI). Zie voor meer informatie en voorbeelden:

Blazor opstarten

Configureer het handmatige begin van het SignalR circuit van Blazorin het App.razor-bestand van een Blazor Web App:

Configureer het handmatige begin van het SignalR circuit van Blazorin het bestand Pages/_Host.cshtml (Blazor Server):

Configureer het handmatige begin van het SignalR circuit van Blazorin het bestand Pages/_Layout.cshtml (Blazor Server):

Configureer het handmatige begin van het SignalR circuit van Blazorin het bestand Pages/_Host.cshtml (Blazor Server):

  • Voeg een kenmerk autostart="false" toe aan de <script>-tag voor het blazor.*.js-script.
  • Plaats een script dat Blazor.start() aanroept nadat het Blazor script is geladen en binnen de afsluitende </body> tag.

Wanneer autostart is uitgeschakeld, werkt elk aspect van de app die niet afhankelijk is van het circuit normaal. Routering aan de clientzijde is bijvoorbeeld operationeel. Elk aspect dat afhankelijk is van het circuit, is echter pas operationeel als Blazor.start() wordt aangeroepen. App-gedrag is onvoorspelbaar zonder een bestaand circuit. Onderdeelmethoden kunnen bijvoorbeeld niet worden uitgevoerd terwijl de verbinding met het circuit is verbroken.

Zie ASP.NET Core Blazor startupvoor meer informatie, waaronder het initialiseren van Blazor wanneer het document klaar is en hoe u een koppeling maakt naar een JS Promise.

SignalR en Keep-Alive configureren op de client

Configureer de volgende waarden voor de client:

  • withServerTimeout: hiermee configureert u de time-out van de server in milliseconden. Als deze time-out is verstreken zonder berichten van de server te ontvangen, wordt de verbinding beëindigd met een fout. De standaardtime-outwaarde is 30 seconden. De time-out van de server moet ten minste twee keer zoveel zijn als de waarde die is toegewezen aan het Keep-Alive interval (withKeepAliveInterval).
  • withKeepAliveInterval: hiermee configureert u het Keep-Alive-interval in milliseconden (standaardinterval om de server te pingen). Met deze instelling kan de server harde ontkoppelingen herkennen, zoals wanneer een client hun computer loskoppelt van het netwerk. De ping treedt maximaal zo vaak op als de server pingt. Als de server elke vijf seconden pingt, zal het toewijzen van een waarde die lager is dan 5000 (5 seconden) resulteren in een ping elke vijf seconden. De standaardwaarde is 15 seconden. Het Keep-Alive interval moet kleiner zijn dan of gelijk zijn aan de helft van de waarde die is toegewezen aan de time-out van de server (withServerTimeout).

In het volgende voorbeeld voor het bestand App.razor (Blazor Web App) wordt de toewijzing van standaardwaarden weergegeven.

Blazor Web App:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    circuit: {
      configureSignalR: function (builder) {
        builder.withServerTimeout(30000).withKeepAliveInterval(15000);
      }
    }
  });
</script>

Het volgende voorbeeld voor het bestand Pages/_Host.cshtml (Blazor Server, alle versies behalve ASP.NET Core in .NET 6) of Pages/_Layout.cshtml bestand (Blazor Server, ASP.NET Core in .NET 6).

Blazor Server:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    configureSignalR: function (builder) {
      builder.withServerTimeout(30000).withKeepAliveInterval(15000);
    }
  });
</script>

In het voorgaande voorbeeld is de placeholder {BLAZOR SCRIPT} het scriptpad en de bestandsnaam Blazor. Zie ASP.NET Core Blazor projectstructuurvoor de locatie van het script en het pad dat u wilt gebruiken.

Wanneer u een hubverbinding in een onderdeel maakt, stelt u de ServerTimeout (standaard: 30 seconden) en KeepAliveInterval (standaard: 15 seconden) in op de HubConnectionBuilder. Stel de HandshakeTimeout (standaard: 15 seconden) in op de ingebouwde HubConnection. In het volgende voorbeeld ziet u de toewijzing van standaardwaarden:

protected override async Task OnInitializedAsync()
{
    hubConnection = new HubConnectionBuilder()
        .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
        .WithServerTimeout(TimeSpan.FromSeconds(30))
        .WithKeepAliveInterval(TimeSpan.FromSeconds(15))
        .Build();

    hubConnection.HandshakeTimeout = TimeSpan.FromSeconds(15);

    hubConnection.On<string, string>("ReceiveMessage", (user, message) => ...

    await hubConnection.StartAsync();
}

Configureer de volgende waarden voor de client:

  • serverTimeoutInMilliseconds: de time-out van de server in milliseconden. Als deze time-out is verstreken zonder berichten van de server te ontvangen, wordt de verbinding beëindigd met een fout. De standaardtime-outwaarde is 30 seconden. De time-out van de server moet ten minste twee keer zoveel zijn als de waarde die is toegewezen aan het Keep-Alive interval (keepAliveIntervalInMilliseconds).
  • keepAliveIntervalInMilliseconds: standaardinterval waarmee de server moet worden pingen. Met deze instelling kan de server harde verbrekingen detecteren, bijvoorbeeld wanneer een client hun computer van het netwerk loskoppelt. De ping treedt maximaal zo vaak op als de server pingt. Als de server elke vijf seconden pingt, leidt het toewijzen van een waarde die lager is dan 5000 (5 seconden) tot pings elke vijf seconden. De standaardwaarde is 15 seconden. Het Keep-Alive interval moet kleiner zijn dan of gelijk zijn aan de helft van de waarde die is toegewezen aan de time-out van de server (serverTimeoutInMilliseconds).

Het volgende voorbeeld voor het Pages/_Host.cshtml-bestand (Blazor Server, alle versies behalve ASP.NET Core in .NET 6) of Pages/_Layout.cshtml bestand (Blazor Server, ASP.NET Core in .NET 6):

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    configureSignalR: function (builder) {
      let c = builder.build();
      c.serverTimeoutInMilliseconds = 30000;
      c.keepAliveIntervalInMilliseconds = 15000;
      builder.build = () => {
        return c;
      };
    }
  });
</script>

In het voorgaande voorbeeld is de placeholder {BLAZOR SCRIPT} het pad naar het script en de bestandsnaam Blazor. Zie ASP.NET Core Blazor projectstructuurvoor de locatie van het script en het pad dat u wilt gebruiken.

Wanneer u een hubverbinding in een onderdeel maakt, stelt u de ServerTimeout (standaard: 30 seconden), HandshakeTimeout (standaard: 15 seconden) en KeepAliveInterval (standaard: 15 seconden) in op de ingebouwde HubConnection. In het volgende voorbeeld ziet u de toewijzing van standaardwaarden:

protected override async Task OnInitializedAsync()
{
    hubConnection = new HubConnectionBuilder()
        .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
        .Build();

    hubConnection.ServerTimeout = TimeSpan.FromSeconds(30);
    hubConnection.HandshakeTimeout = TimeSpan.FromSeconds(15);
    hubConnection.KeepAliveInterval = TimeSpan.FromSeconds(15);

    hubConnection.On<string, string>("ReceiveMessage", (user, message) => ...

    await hubConnection.StartAsync();
}

Bij het wijzigen van de waarden van de servertime-out (ServerTimeout) of het Keep-Alive interval (KeepAliveInterval):

  • De time-out van de server moet ten minste twee keer zoveel zijn als de waarde die is toegewezen aan het Keep-Alive interval.
  • Het Keep-Alive interval moet kleiner dan of gelijk zijn aan de helft van de waarde die is toegewezen aan de time-out van de server.

Zie de algemene implementatie- en verbindingsfouten secties van de volgende artikelen voor meer informatie:

De handler voor opnieuw verbinden aan de serverzijde wijzigen

De circuitverbindingsevenementen van de handler voor opnieuw verbinden kunnen worden gewijzigd voor aangepast gedrag, zoals:

  • Om de gebruiker op de hoogte te stellen als de verbinding is verbroken.
  • Logboekregistratie (vanaf de client) uitvoeren wanneer een circuit is verbonden.

Als u de verbindingsevenementen wilt wijzigen, registreert u callbacks voor de volgende verbindingswijzigingen:

  • Verbroken verbindingen maken gebruik van onConnectionDown.
  • Tot stand gebrachte/opnieuw tot stand gebrachte verbindingen maken gebruik van onConnectionUp.

Zowel onConnectionDown als onConnectionUp moet worden opgegeven.

Blazor Web App:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    circuit: {
      reconnectionHandler: {
        onConnectionDown: (options, error) => console.error(error),
        onConnectionUp: () => console.log("Up, up, and away!")
      }
    }
  });
</script>

Blazor Server:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    reconnectionHandler: {
      onConnectionDown: (options, error) => console.error(error),
      onConnectionUp: () => console.log("Up, up, and away!")
    }
  });
</script>

In het voorgaande voorbeeld is de placeholder {BLAZOR SCRIPT} het scriptpad en de bestandsnaam Blazor. Zie ASP.NET Core Blazor projectstructuurvoor de locatie van het script en het pad dat u wilt gebruiken.

De pagina automatisch vernieuwen wanneer de verbinding aan de serverzijde mislukt

Voor het standaardgedrag voor opnieuw verbinden moet de gebruiker handmatig actie ondernemen om de pagina te vernieuwen nadat de verbinding is mislukt. Een aangepaste handler voor opnieuw verbinden kan echter worden gebruikt om de pagina automatisch te vernieuwen:

App.razor:

Pages/_Host.cshtml:

<div id="reconnect-modal" style="display: none;"></div>
<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script src="boot.js"></script>

In het voorgaande voorbeeld is de tijdelijke aanduiding {BLAZOR SCRIPT} het pad en de bestandsnaam van het script Blazor. Zie ASP.NET Core Blazor projectstructuurvoor de locatie van het script en het pad dat u wilt gebruiken.

Maak het volgende wwwroot/boot.js bestand.

Blazor Web App:

(() => {
  const maximumRetryCount = 3;
  const retryIntervalMilliseconds = 5000;
  const reconnectModal = document.getElementById('reconnect-modal');

  const startReconnectionProcess = () => {
    reconnectModal.style.display = 'block';

    let isCanceled = false;

    (async () => {
      for (let i = 0; i < maximumRetryCount; i++) {
        reconnectModal.innerText = `Attempting to reconnect: ${i + 1} of ${maximumRetryCount}`;

        await new Promise(resolve => setTimeout(resolve, retryIntervalMilliseconds));

        if (isCanceled) {
          return;
        }

        try {
          const result = await Blazor.reconnect();
          if (!result) {
            // The server was reached, but the connection was rejected; reload the page.
            location.reload();
            return;
          }

          // Successfully reconnected to the server.
          return;
        } catch {
          // Didn't reach the server; try again.
        }
      }

      // Retried too many times; reload the page.
      location.reload();
    })();

    return {
      cancel: () => {
        isCanceled = true;
        reconnectModal.style.display = 'none';
      },
    };
  };

  let currentReconnectionProcess = null;

  Blazor.start({
    circuit: {
      reconnectionHandler: {
        onConnectionDown: () => currentReconnectionProcess ??= startReconnectionProcess(),
        onConnectionUp: () => {
          currentReconnectionProcess?.cancel();
          currentReconnectionProcess = null;
        }
      }
    }
  });
})();

Blazor Server:

(() => {
  const maximumRetryCount = 3;
  const retryIntervalMilliseconds = 5000;
  const reconnectModal = document.getElementById('reconnect-modal');

  const startReconnectionProcess = () => {
    reconnectModal.style.display = 'block';

    let isCanceled = false;

    (async () => {
      for (let i = 0; i < maximumRetryCount; i++) {
        reconnectModal.innerText = `Attempting to reconnect: ${i + 1} of ${maximumRetryCount}`;

        await new Promise(resolve => setTimeout(resolve, retryIntervalMilliseconds));

        if (isCanceled) {
          return;
        }

        try {
          const result = await Blazor.reconnect();
          if (!result) {
            // The server was reached, but the connection was rejected; reload the page.
            location.reload();
            return;
          }

          // Successfully reconnected to the server.
          return;
        } catch {
          // Didn't reach the server; try again.
        }
      }

      // Retried too many times; reload the page.
      location.reload();
    })();

    return {
      cancel: () => {
        isCanceled = true;
        reconnectModal.style.display = 'none';
      },
    };
  };

  let currentReconnectionProcess = null;

  Blazor.start({
    reconnectionHandler: {
      onConnectionDown: () => currentReconnectionProcess ??= startReconnectionProcess(),
      onConnectionUp: () => {
        currentReconnectionProcess?.cancel();
        currentReconnectionProcess = null;
      }
    }
  });
})();

Zie ASP.NET Core Blazor startupvoor meer informatie over Blazor opstarten.

Het aantal herstelaansluitingpogingen en het interval aan de serverzijde aanpassen

Als u het aantal nieuwe pogingen en interval wilt aanpassen, stelt u het aantal nieuwe pogingen (maxRetries) en de periode in milliseconden in die zijn toegestaan voor elke nieuwe poging (retryIntervalMilliseconds).

Blazor Web App:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    circuit: {
      reconnectionOptions: {
        maxRetries: 3,
        retryIntervalMilliseconds: 2000
      }
    }
  });
</script>

Blazor Server:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    reconnectionOptions: {
      maxRetries: 3,
      retryIntervalMilliseconds: 2000
    }
  });
</script>

In het voorgaande voorbeeld is de tijdelijke aanduiding {BLAZOR SCRIPT} het scriptpad Blazor en de bestandsnaam Blazor. Zie ASP.NET Core Blazor projectstructuurvoor de locatie van het script en het pad dat u wilt gebruiken.

Wanneer de gebruiker terug navigeert naar een app met een niet-verbonden circuit, wordt er onmiddellijk opnieuw verbinding gemaakt in plaats van te wachten op de duur van het volgende interval voor opnieuw verbinden. Dit gedrag probeert de verbinding zo snel mogelijk voor de gebruiker te hervatten.

De standaardinstelling voor herverbinden maakt gebruik van een berekende backoff-strategie. De eerste pogingen om opnieuw verbinding te maken, worden snel achter elkaar uitgevoerd voordat berekende vertragingen tussen pogingen worden geïntroduceerd. De standaardlogica voor het berekenen van het interval voor opnieuw proberen is een implementatiedetail die zonder kennisgeving kan worden gewijzigd, maar u kunt de standaardlogica vinden die het Blazor framework gebruikt in de computeDefaultRetryInterval-functie (referentiebron).

Notitie

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-branche of tags uitklaplijst. Zie Een versietag selecteren van ASP.NET Core-broncode (dotnet/AspNetCore.Docs #26205)voor meer informatie.

Pas het intervalgedrag voor opnieuw proberen aan door een functie op te geven om het interval voor opnieuw proberen te berekenen. In het volgende voorbeeld van exponentieel uitstel wordt het aantal eerdere pogingen voor opnieuw verbinden vermenigvuldigd met 1000 ms om het interval voor opnieuw proberen te berekenen. Wanneer het aantal eerdere pogingen om opnieuw verbinding te maken (previousAttempts) groter is dan de maximumlimiet voor opnieuw proberen (maxRetries), wordt null toegewezen als poging-interval (retryIntervalMilliseconds) om verdere pogingen om opnieuw verbinding te maken te stoppen.

Blazor.start({
  circuit: {
    reconnectionOptions: {
      retryIntervalMilliseconds: (previousAttempts, maxRetries) => 
        previousAttempts >= maxRetries ? null : previousAttempts * 1000
    },
  },
});

Een alternatief is het opgeven van de exacte reeks intervallen voor opnieuw proberen. Na het laatste opgegeven interval voor opnieuw proberen, worden nieuwe pogingen gestopt omdat de retryIntervalMilliseconds functie undefinedretourneert:

Blazor.start({
  circuit: {
    reconnectionOptions: {
      retryIntervalMilliseconds: 
        Array.prototype.at.bind([0, 1000, 2000, 5000, 10000, 15000, 30000]),
    },
  },
});

Voor meer informatie over Blazor startup, zie ASP.NET Core Blazor startup.

Bepalen wanneer de gebruikersinterface voor opnieuw verbinden wordt weergegeven

Bepalen wanneer de gebruikersinterface voor opnieuw verbinding wordt weergegeven, kan handig zijn in de volgende situaties:

  • Een geïmplementeerde app geeft regelmatig de gebruikersinterface voor opnieuw verbinding weer vanwege time-outs voor ping die worden veroorzaakt door interne netwerk- of internetlatentie en u wilt de vertraging verhogen.
  • Een app moet gebruikers melden dat de verbinding eerder is verbroken en u wilt de vertraging verkorten.

De timing van het verschijnen van de gebruikersinterface voor opnieuw verbinden wordt beïnvloed door het aanpassen van het Keep-Alive-interval en de time-outs op de client. De gebruikersinterface voor opnieuw verbinden wordt weergegeven wanneer de time-out van de server is bereikt op de client (withServerTimeout, clientconfiguratie sectie). Het wijzigen van de waarde van withServerTimeout vereist echter wijzigingen in andere Keep-Alive-, time-out- en handshake-instellingen die worden beschreven in de volgende richtlijnen.

Als algemene aanbevelingen voor de volgende richtlijnen:

  • Het Keep-Alive interval moet overeenkomen tussen client- en serverconfiguraties.
  • Time-outs moeten minimaal het dubbele zijn van de waarde die aan het Keep-Alive-interval is toegewezen.

Serverconfiguratie

Stel het volgende in:

  • ClientTimeoutInterval (standaard: 30 seconden): De tijdvensterclients moeten een bericht verzenden voordat de server de verbinding sluit.
  • HandshakeTimeout (standaard: 15 seconden): het interval dat door de server wordt gebruikt voor time-out van binnenkomende handshake-aanvragen door clients.
  • KeepAliveInterval (standaard: 15 seconden): het interval dat door de server wordt gebruikt om keep-alive pings naar verbonden klanten te sturen. Let op dat er ook een Keep-Alive-intervalinstelling op de client is, die moet overeenkomen met de waarde van de server.

De ClientTimeoutInterval en HandshakeTimeout kunnen worden verhoogd en de KeepAliveInterval kunnen hetzelfde blijven. Het belangrijkste is dat als u de waarden wijzigt, ervoor zorgt dat de time-outs ten minste een dubbele waarde hebben van het Keep-Alive interval en dat het Keep-Alive interval overeenkomt tussen server en client. Zie de Time-outs voor SignalR configureren en Keep-Alive in de sectie van de client voor meer informatie.

In het volgende voorbeeld:

  • De ClientTimeoutInterval wordt verhoogd tot 60 seconden (standaardwaarde: 30 seconden).
  • De HandshakeTimeout wordt verhoogd tot 30 seconden (standaardwaarde: 15 seconden).
  • De KeepAliveInterval is niet ingesteld in ontwikkelaarscode en gebruikt de standaardwaarde van 15 seconden. Als u de waarde van het Keep-Alive interval verlaagt, wordt de frequentie van communicatie-pings verhoogd, waardoor de belasting van de app, server en het netwerk toeneemt. Er moet voor worden gezorgd dat er geen slechte prestaties ontstaan bij het verlagen van het Keep-Alive interval.

Blazor Web App (.NET 8 of hoger) in het Program-bestand van het serverproject:

builder.Services.AddRazorComponents().AddInteractiveServerComponents()
    .AddHubOptions(options =>
{
    options.ClientTimeoutInterval = TimeSpan.FromSeconds(60);
    options.HandshakeTimeout = TimeSpan.FromSeconds(30);
});

Blazor Server in het bestand Program:

builder.Services.AddServerSideBlazor()
    .AddHubOptions(options =>
    {
        options.ClientTimeoutInterval = TimeSpan.FromSeconds(60);
        options.HandshakeTimeout = TimeSpan.FromSeconds(30);
    });

Zie de sectie circuithandleropties aan de serverzijde voor meer informatie.

Clientconfiguratie

Stel het volgende in:

  • withServerTimeout (standaard: 30 seconden): Hiermee configureert u de servertime-out, opgegeven in milliseconden, voor de hubverbinding van het circuit.
  • withKeepAliveInterval (standaard: 15 seconden): het interval, opgegeven in milliseconden, waarmee de verbinding Keep-Alive berichten verzendt.

De time-out van de server kan worden verhoogd en het Keep-Alive interval kan hetzelfde blijven. Het belangrijkste is dat als u de waarden wijzigt, ervoor zorgt dat de time-out van de server ten minste het dubbele is van de waarde van het Keep-Alive interval en dat de Keep-Alive intervalwaarden overeenkomen tussen server en client. Voor meer informatie kunt u de sectie van de client raadplegen: Configure SignalR time-outs en Keep-Alive.

In het volgende opstartconfiguratie voorbeeld (locatie van het Blazor script), wordt een aangepaste waarde van 60 seconden gebruikt voor de servertime-out. Het Keep-Alive interval (withKeepAliveInterval) is niet ingesteld en gebruikt de standaardwaarde van 15 seconden.

Blazor Web App:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    circuit: {
      configureSignalR: function (builder) {
        builder.withServerTimeout(60000);
      }
    }
  });
</script>

Blazor Server:

<script src="{BLAZOR SCRIPT}" autostart="false"></script>
<script>
  Blazor.start({
    configureSignalR: function (builder) {
      builder.withServerTimeout(60000);
    }
  });
</script>

Wanneer u een hubverbinding in een onderdeel maakt, stelt u de time-out van de server (WithServerTimeout, standaard: 30 seconden) in op de HubConnectionBuilder. Stel de HandshakeTimeout (standaard: 15 seconden) in op de ingebouwde HubConnection. Controleer of de timeouts ten minste het dubbele van het Keep-Alive-interval (WithKeepAliveInterval/KeepAliveInterval) zijn en of de Keep-Alive-waarde overeenkomt tussen de server en de client.

Het volgende voorbeeld is gebaseerd op de Index component in de SignalR met de Blazor handleiding. De time-out van de server wordt verhoogd tot 60 seconden en de time-out voor handshake wordt verhoogd tot 30 seconden. Het Keep-Alive interval is niet ingesteld en gebruikt de standaardwaarde van 15 seconden.

protected override async Task OnInitializedAsync()
{
    hubConnection = new HubConnectionBuilder()
        .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
        .WithServerTimeout(TimeSpan.FromSeconds(60))
        .Build();

    hubConnection.HandshakeTimeout = TimeSpan.FromSeconds(30);

    hubConnection.On<string, string>("ReceiveMessage", (user, message) => ...

    await hubConnection.StartAsync();
}

Stel het volgende in:

  • serverTimeoutInMilliseconds (standaard: 30 seconden): Hiermee configureert u de servertime-out, opgegeven in milliseconden, voor de hubverbinding van het circuit.
  • keepAliveIntervalInMilliseconds (standaard: 15 seconden): het interval, opgegeven in milliseconden, waarmee de verbinding Keep-Alive berichten verzendt.

De time-out van de server kan worden verhoogd en het Keep-Alive interval kan hetzelfde blijven. Het belangrijkste is dat als u de waarden wijzigt, ervoor zorgt dat de time-out van de server ten minste het dubbele is van de waarde van het Keep-Alive interval en dat de Keep-Alive intervalwaarden overeenkomen tussen server en client. Zie de Time-outs voor SignalR configureren en Keep-Alive in de sectie van de client voor meer informatie.

In het volgende opstartconfiguratie voorbeeld (locatie van het Blazor script), wordt een aangepaste waarde van 60 seconden gebruikt voor de servertime-out. Het Keep-Alive interval (keepAliveIntervalInMilliseconds) is niet ingesteld en gebruikt de standaardwaarde van 15 seconden.

In Pages/_Host.cshtml:

<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
  Blazor.start({
    configureSignalR: function (builder) {
      let c = builder.build();
      c.serverTimeoutInMilliseconds = 60000;
      builder.build = () => {
        return c;
      };
    }
  });
</script>

Wanneer u een hubverbinding in een onderdeel maakt, stelt u de ServerTimeout (standaard: 30 seconden) en HandshakeTimeout (standaard: 15 seconden) in op de ingebouwde HubConnection. Controleer of de time-outs ten minste het dubbele van het Keep-Alive-interval zijn. Controleer of het Keep-Alive interval overeenkomt met de server en de client.

Het volgende voorbeeld is gebaseerd op het Index-onderdeel in de SignalR-handleiding met Blazor. De ServerTimeout wordt verhoogd tot 60 seconden en de HandshakeTimeout wordt verhoogd tot 30 seconden. Het Keep-Alive interval (KeepAliveInterval) is niet ingesteld en gebruikt de standaardwaarde van 15 seconden.

protected override async Task OnInitializedAsync()
{
    hubConnection = new HubConnectionBuilder()
        .WithUrl(Navigation.ToAbsoluteUri("/chathub"))
        .Build();

    hubConnection.ServerTimeout = TimeSpan.FromSeconds(60);
    hubConnection.HandshakeTimeout = TimeSpan.FromSeconds(30);

    hubConnection.On<string, string>("ReceiveMessage", (user, message) => ...

    await hubConnection.StartAsync();
}

Verbreek de verbinding van circuit Blazor's SignalR met de client.

Blazor SignalR circuit wordt verbroken wanneer het unload pagina-evenement wordt geactiveerd. Als u de verbinding met het circuit voor andere scenario's op de client wilt verbreken, roept u Blazor.disconnect aan in de juiste gebeurtenis-handler. In het volgende voorbeeld wordt de verbinding met het circuit verbroken wanneer de pagina is verborgen (pagehide gebeurtenis):

window.addEventListener('pagehide', () => {
  Blazor.disconnect();
});

Voor meer informatie over Blazor opstart, zie ASP.NET Core Blazor startup.

Circuithandler aan serverzijde

U kunt een circuithandler definiëren, waarmee code kan worden uitgevoerd op wijzigingen in de status van het circuit van een gebruiker. Een circuithandler wordt geïmplementeerd door te worden afgeleid van CircuitHandler en de klasse te registreren in de servicecontainer van de app. In het volgende voorbeeld van een circuithandler worden geopende SignalR verbindingen bijgehouden.

TrackingCircuitHandler.cs:

using Microsoft.AspNetCore.Components.Server.Circuits;

public class TrackingCircuitHandler : CircuitHandler
{
    private HashSet<Circuit> circuits = new();

    public override Task OnConnectionUpAsync(Circuit circuit, 
        CancellationToken cancellationToken)
    {
        circuits.Add(circuit);

        return Task.CompletedTask;
    }

    public override Task OnConnectionDownAsync(Circuit circuit, 
        CancellationToken cancellationToken)
    {
        circuits.Remove(circuit);

        return Task.CompletedTask;
    }

    public int ConnectedCircuits => circuits.Count;
}

Circuithandlers worden geregistreerd met behulp van DI. Scoped exemplaren worden per exemplaar van een circuit gemaakt. Met behulp van de TrackingCircuitHandler in het vorige voorbeeld wordt een singleton-service gemaakt omdat de status van alle circuits moet worden bijgehouden.

In het bestand Program:

builder.Services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();

In Startup.ConfigureServices van Startup.cs:

services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();

Als de methoden van een aangepaste circuithandler een onbehandelde uitzondering veroorzaken, is de uitzondering fataal voor het circuit. Als u uitzonderingen in de code of methoden van een handler wilt tolereren, verpakt u de code in een of meer try-catch instructies met foutafhandeling en logboekregistratie.

Wanneer een circuit eindigt omdat een gebruiker de verbinding heeft verbroken en het framework de circuitstatus opschoont, wordt het DI-bereik van het circuit verwijderd. Als u het bereik verwijdert, worden alle di-services met circuitbereik verwijderd die System.IDisposableimplementeren. Als een DI-service een onverwerkte uitzondering genereert tijdens het verwijderen, registreert het framework de uitzondering. Zie ASP.NET Core Blazor dependency injectionvoor meer informatie.

Circuithandler aan de serverzijde om gebruikers te registreren voor aangepaste diensten

Gebruik een CircuitHandler om een gebruiker vast te leggen uit de AuthenticationStateProvider en die gebruiker in een service in te stellen. Zie ASP.NET Core-serverzijde en Blazor Web App aanvullende beveiligingsscenario'svoor meer informatie en voorbeeldcode.

Sluiting van circuits wanneer er geen resterende interactieve serveronderdelen zijn

Interactieve Server-onderdelen verwerken webgebruikersinterfacegebeurtenissen met behulp van een realtime-verbinding met de browser die een circuit wordt genoemd. Een circuit en de bijbehorende status worden gemaakt wanneer een interactive server-hoofdonderdeel wordt weergegeven. Het circuit wordt gesloten wanneer er geen resterende interactieve serveronderdelen op de pagina zijn, waardoor serverbronnen worden vrijgemaakt.

Het SignalR circuit op een andere URL starten

Voorkom dat de app automatisch wordt gestart door autostart="false" toe te voegen aan de Blazor<script> tag (locatie van het Blazor startscript). Stel de circuit-URL handmatig in met behulp van Blazor.start. In de volgende voorbeelden wordt het pad /signalrgebruikt.

Blazor Web Apps:

- <script src="_framework/blazor.web.js"></script>
+ <script src="_framework/blazor.web.js" autostart="false"></script>
+ <script>
+   Blazor.start({
+     circuit: {
+       configureSignalR: builder => builder.withUrl("/signalr")
+     },
+   });
+ </script>

Blazor Server:

- <script src="_framework/blazor.server.js"></script>
+ <script src="_framework/blazor.server.js" autostart="false"></script>
+ <script>
+   Blazor.start({
+     configureSignalR: builder => builder.withUrl("/signalr")
+   });
+ </script>

Voeg de volgende MapBlazorHub-aanroep toe met het hubpad aan de middleware-verwerkingspijplijn in het Program-bestand van de server-app.

Blazor Web Apps:

app.MapBlazorHub("/signalr");

Blazor Server:

Laat de bestaande aanroep MapBlazorHub in het bestand en voeg een nieuwe aanroep toe aan MapBlazorHub met het pad:

app.MapBlazorHub();
+ app.MapBlazorHub("/signalr");

IHttpContextAccessor/HttpContext

IHttpContextAccessor over het algemeen moet worden vermeden met interactieve rendering, omdat een geldige HttpContext niet altijd beschikbaar is.

IHttpContextAccessor kunnen worden gebruikt voor onderdelen die statisch worden weergegeven op de server. We raden u echter aan deze indien mogelijk te vermijden.

HttpContext kan worden gebruikt als een trapsgewijze parameter alleen in statisch gerenderde hoofdonderdelen voor algemene taken, zoals het inspecteren en wijzigen van headers of andere eigenschappen in het App onderdeel (Components/App.razor). De waarde wordt altijd null voor interactieve rendering.

[CascadingParameter]
public HttpContext? HttpContext { get; set; }

Voor scenario's waarbij de HttpContext vereist is in interactieve onderdelen, raden we u aan om de gegevens via de status van een permanent onderdeel vanaf de server te laten stromen. Zie ASP.NET Core-serverzijde en Blazor Web App aanvullende beveiligingsscenario'svoor meer informatie.

Gebruik IHttpContextAccessor/HttpContext niet direct of indirect in de Razor onderdelen van Blazor-apps aan de serverzijde. Blazor apps worden uitgevoerd buiten de context van de ASP.NET Core-pijplijn. De HttpContext is niet gegarandeerd beschikbaar in de IHttpContextAccessoren HttpContext is niet gegarandeerd de context te behouden waarmee de Blazor-app is gestart.

De aanbevolen methode voor het doorgeven van de status van de aanvraag aan de Blazor-app is via de parameters van het hoofdonderdeel tijdens de eerste rendering van de app. De app kan de gegevens ook kopiëren naar een scoped service in de initialisatielevenscyclusgebeurtenis van het rootcomponent voor gebruik in de hele app. Zie ASP.NET Core-serverzijde en Blazor Web App aanvullende beveiligingsscenario'svoor meer informatie.

Een essentieel aspect van Blazor beveiliging aan de serverzijde is dat de gebruiker die aan een bepaald circuit is gekoppeld, op een bepaald moment kan worden bijgewerkt nadat het Blazor circuit tot stand is gebracht, maar de IHttpContextAccessorniet wordt bijgewerkt. Zie ASP.NET Core-serverzijde en Blazor Web App aanvullende beveiligingsscenario'svoor meer informatie over het aanpakken van deze situatie met aangepaste services.

Imitatie voor Windows-verificatie

Geverifieerde hubverbindingen (HubConnection) worden gemaakt met UseDefaultCredentials om het gebruik van standaardreferenties voor HTTP-aanvragen aan te geven. Zie Verificatie en autorisatie in ASP.NET Core SignalRvoor meer informatie.

Wanneer de app wordt uitgevoerd in IIS Express als de aangemelde gebruiker onder Windows-verificatie, wat waarschijnlijk het persoonlijke of werkaccount van de gebruiker is, zijn de standaardreferenties die van de aangemelde gebruiker.

Wanneer de app wordt gepubliceerd naar IIS, wordt de app uitgevoerd onder de groep van toepassingen Identity. De HubConnection maakt verbinding als het IIS-gebruikersaccount dat als host fungeert voor de app, niet de gebruiker die de pagina opent.

Implementeer impersonatie met de HubConnection om de identiteit van de gebruiker tijdens browsen te gebruiken.

In het volgende voorbeeld:

protected override async Task OnInitializedAsync()
{
    var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();

    if (authState?.User.Identity is not null)
    {
        var user = authState.User.Identity as WindowsIdentity;

        if (user is not null)
        {
            await WindowsIdentity.RunImpersonatedAsync(user.AccessToken, 
                async () =>
                {
                    hubConnection = new HubConnectionBuilder()
                        .WithUrl(NavManager.ToAbsoluteUri("/hub"), config =>
                        {
                            config.UseDefaultCredentials = true;
                        })
                        .WithAutomaticReconnect()
                        .Build();

                        hubConnection.On<string>("name", userName =>
                        {
                            name = userName;
                            InvokeAsync(StateHasChanged);
                        });

                        await hubConnection.StartAsync();
                });
        }
    }
}

In de voorgaande code is NavManager een NavigationManageren AuthenticationStateProvider een AuthenticationStateProvider service-instantie (AuthenticationStateProvider documentatie).

Aanvullende bronnen aan de serverzijde