wskazówki dotyczące platformy ASP.NET Core BlazorSignalR

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zapoznaj się z wersją tego artykułu platformy .NET 8.

W tym artykule wyjaśniono, jak konfigurować połączenia w Blazor aplikacjach i zarządzać nimiSignalR.

Aby uzyskać ogólne wskazówki dotyczące konfiguracji ASP.NET CoreSignalR, zobacz tematy w temacie Omówienie ASP.NET Core SignalR w dokumentacji, szczególnie w konfiguracji ASP.NET CoreSignalR.

Aplikacje po stronie serwera używają ASP.NET Core SignalR do komunikowania się z przeglądarką. SignalRWarunki hostingu i skalowania mają zastosowanie do aplikacji po stronie serwera.

Blazor działa najlepiej w przypadku korzystania z obiektów WebSocket jako SignalR transportu ze względu na mniejsze opóźnienia, niezawodność i bezpieczeństwo. Długie sondowanie jest używane, SignalR gdy zestawy WebSocket nie są dostępne lub gdy aplikacja jest jawnie skonfigurowana do korzystania z długiego sondowania.

Kompresja protokołu WebSocket dla składników interactive server

Domyślnie składniki interaktywnego serwera:

  • Włącz kompresję dla połączeń protokołu WebSocket. ConfigureWebsocketOptions steruje kompresją protokołu WebSocket.

  • frame-ancestorsPrzyjęcie dyrektywy zasad zabezpieczeń zawartości (CSP) ustawionej na 'self'wartość , która zezwala tylko na osadzanie aplikacji w miejscu pochodzenia, z którego aplikacja jest obsługiwana, <iframe> gdy kompresja jest włączona lub gdy podano konfigurację kontekstu protokołu WebSocket. ContentSecurityFrameAncestorPolicy steruje dostawcą frame-ancestors CSP.

Dostawca frame-ancestors CSP można usunąć ręcznie, ustawiając wartość ConfigureWebSocketOptions na null, ponieważ można skonfigurować dostawcę CSP w scentralizowany sposób. frame-ancestors Gdy dostawca usług kryptograficznych jest zarządzany w sposób scentralizowany, należy zadbać o zastosowanie zasad za każdym razem, gdy pierwszy dokument jest renderowany. Nie zalecamy całkowitego usuwania zasad, ponieważ może to spowodować, że aplikacja będzie podatna na ataki.

Przykłady użycia:

Wyłącz kompresję, ustawiając wartość ConfigureWebSocketOptionsnull, co zmniejsza lukę w zabezpieczeniach aplikacji do ataku , ale może spowodować zmniejszenie wydajności:

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

Po włączeniu kompresji należy skonfigurować bardziej frame-ancestors rygorystyczny dostawca usług kryptograficznych z wartością 'none' (wymagane pojedyncze cudzysłowy), co umożliwia kompresję protokołu WebSocket, ale uniemożliwia przeglądarkom osadzanie aplikacji w dowolnym elemencie <iframe>:

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

Po włączeniu kompresji usuń dostawcę frame-ancestors CSP, ustawiając wartość nullContentSecurityFrameAncestorsPolicy . Ten scenariusz jest zalecany tylko w przypadku aplikacji, które ustawiają dostawcę CSP w scentralizowany sposób:

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

Ważne

Przeglądarki stosują dyrektywy CSP z wielu nagłówków CSP przy użyciu najściślejszej wartości dyrektywy zasad. W związku z tym deweloper nie może dodać słabszych frame-ancestors zasad niż 'self' celowo ani przez pomyłkę.

Pojedyncze cudzysłowy są wymagane dla wartości ciągu przekazanej do ContentSecurityFrameAncestorsPolicyelementu :

Nieobsługiwane wartości:none, self

'self'

Dodatkowe opcje obejmują określanie co najmniej jednego źródła hosta i źródeł schematu.

Aby uzyskać informacje na temat wpływu na zabezpieczenia, zobacz Wskazówki dotyczące ograniczania zagrożeń dotyczące renderowania interaktywnego po stronie serwera ASP.NET CoreBlazor. Aby uzyskać więcej informacji na frame-ancestors temat dyrektywy, zobacz CSP: frame-ancestors (dokumentacja MDN).

Wyłączanie kompresji odpowiedzi dla Przeładowywanie na gorąco

W przypadku korzystania z Przeładowywanie na gorąco wyłącz oprogramowanie pośredniczące kompresji odpowiedzi w Development środowisku. Niezależnie od tego, czy jest używany domyślny kod z szablonu projektu, zawsze należy wywołać UseResponseCompression najpierw w potoku przetwarzania żądań.

W pliku Program:

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

Negocjacje między źródłami po stronie SignalR klienta na potrzeby uwierzytelniania

W tej sekcji wyjaśniono, jak skonfigurować SignalRbazowego klienta do wysyłania poświadczeń, takich jak cookienagłówki uwierzytelniania HTTP lub s.

Służy SetBrowserRequestCredentials do ustawiania Include żądań między źródłami fetch .

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);
    }
}

W przypadku skompilowania połączenia koncentratora przypisz HttpMessageHandler tę opcję:HttpMessageHandlerFactory

private HubConnectionBuilder? hubConnection;

...

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

W poprzednim przykładzie adres URL połączenia koncentratora jest konfigurowany na bezwzględny adres URI pod adresem /chathub. Identyfikator URI można również ustawić za pomocą ciągu, na przykład https://signalr.example.com, lub za pośrednictwem konfiguracji. Navigation jest wstrzykniętym NavigationManagerelementem .

Aby uzyskać więcej informacji, zobacz ASP.NET Core configuration (Konfiguracja ASP.NET CoreSignalR).

Renderowanie po stronie klienta

W przypadku skonfigurowania prerenderingu przed nawiązaniem połączenia klienta z serwerem następuje wstępneenderowanie. Aby uzyskać więcej informacji, zobacz Prerender ASP.NET Core components (Składniki prerender ASP.NET CoreRazor).

W przypadku skonfigurowania prerenderingu przed nawiązaniem połączenia klienta z serwerem następuje wstępneenderowanie. Aby uzyskać więcej informacji, zobacz następujące artykuły:

Rozmiar stanu wstępnego i SignalR limit rozmiaru komunikatu

Duży rozmiar stanu wstępnego może przekroczyć limit rozmiaru komunikatu obwodu SignalR , co powoduje następujące kwestie:

  • Nie SignalR można zainicjować obwodu z powodu błędu na kliencie: Circuit host not initialized.
  • Po awarii obwodu zostanie wyświetlone okno dialogowe ponownego nawiązywania połączenia na kliencie. Odzyskiwanie nie jest możliwe.

Aby rozwiązać ten problem, użyj jednej z następujących metod:

  • Zmniejsz ilość danych umieszczanych w stanie wstępnie utworzonym.
  • Zwiększ limit rozmiaru komunikatu.SignalR OSTRZEŻENIE: Zwiększenie limitu może zwiększyć ryzyko ataków typu "odmowa usługi" (DoS).

Dodatkowe zasoby po stronie klienta

Używanie sesji sticky na potrzeby hostingu farmy internetowej po stronie serwera

Prerenders Blazor aplikacji w odpowiedzi na pierwsze żądanie klienta, które tworzy stan interfejsu użytkownika na serwerze. Gdy klient próbuje utworzyć SignalR połączenie, klient musi ponownie nawiązać połączenie z tym samym serwerem. Gdy jest używany więcej niż jeden serwer zaplecza, aplikacja powinna implementować sesje sticky dla SignalR połączeń.

Uwaga

Następujący błąd jest zgłaszany przez aplikację, która nie włączyła sesji sticky w farmie internetowej:

blazor.server.js:1 Uncaught (w obietnicy) Błąd: wywołanie anulowane z powodu zamknięcia połączenia bazowego.

Usługa platformy Azure SignalR po stronie serwera

Zalecamy używanie usługi platformy Azure SignalR na potrzeby programowania po stronie serwera hostowanego na platformie Microsoft Azure. Usługa działa w połączeniu z centrum aplikacji Blazor w celu skalowania aplikacji w górę aplikacji po stronie serwera do dużej liczby współbieżnych SignalR połączeń. Ponadto SignalR globalne zasięg usługi i centra danych o wysokiej wydajności znacznie pomagają zmniejszyć opóźnienie ze względu na lokalizację geograficzną.

Sesje sticky są włączone dla usługi platformy Azure SignalR przez ustawienie opcji usługi ServerStickyMode lub wartości konfiguracji na Required. Aby uzyskać więcej informacji, zobacz Hostowanie i wdrażanie aplikacji po stronie Blazor serwera ASP.NET Core.

Opcje obsługi obwodu po stronie serwera

Skonfiguruj obwód za pomocą polecenia CircuitOptions. Wyświetl wartości domyślne w źródle odwołania.

Uwaga

Linki dokumentacji do źródła referencyjnego platformy .NET zwykle ładują domyślną gałąź repozytorium, która odzwierciedla bieżące programowanie dla następnej wersji platformy .NET. Aby wybrać tag dla określonej wersji, użyj listy rozwijanej Przełącz gałęzie lub tagi. Aby uzyskać więcej informacji, zobacz Jak wybrać tag wersji kodu źródłowego platformy ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Odczytywanie lub ustawianie opcji w Program pliku za pomocą delegata opcji na AddInteractiveServerComponents. Symbol {OPTION} zastępczy reprezentuje opcję, a {VALUE} symbol zastępczy jest wartością.

W pliku Program:

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

Odczytywanie lub ustawianie opcji w Program pliku za pomocą delegata opcji na AddServerSideBlazor. Symbol {OPTION} zastępczy reprezentuje opcję, a {VALUE} symbol zastępczy jest wartością.

W pliku Program:

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

Przeczytaj lub ustaw opcje w programie Startup.ConfigureServices za pomocą delegata opcji na AddServerSideBlazor. Symbol {OPTION} zastępczy reprezentuje opcję, a {VALUE} symbol zastępczy jest wartością.

W Startup.ConfigureServices pliku :Startup.cs

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

Aby skonfigurować element HubConnectionContext, użyj polecenia z AddHubOptions.HubConnectionContextOptions Wyświetl wartości domyślne opcji kontekstu połączenia centrum w źródle referencyjnym. Opisy opcji w SignalR dokumentacji można znaleźć w artykule ASP.NET Core configuration (Konfiguracja ASP.NET CoreSignalR). Symbol {OPTION} zastępczy reprezentuje opcję, a {VALUE} symbol zastępczy jest wartością.

Uwaga

Linki dokumentacji do źródła referencyjnego platformy .NET zwykle ładują domyślną gałąź repozytorium, która odzwierciedla bieżące programowanie dla następnej wersji platformy .NET. Aby wybrać tag dla określonej wersji, użyj listy rozwijanej Przełącz gałęzie lub tagi. Aby uzyskać więcej informacji, zobacz Jak wybrać tag wersji kodu źródłowego platformy ASP.NET Core (dotnet/AspNetCore.Docs #26205).

W pliku Program:

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

W pliku Program:

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

W Startup.ConfigureServices pliku :Startup.cs

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

Ostrzeżenie

Wartość domyślna to MaximumReceiveMessageSize 32 KB. Zwiększenie wartości może zwiększyć ryzyko ataków typu "odmowa usługi" (DoS).

Aby uzyskać informacje na temat zarządzania pamięcią, zobacz Hostowanie i wdrażanie aplikacji po stronie Blazor serwera ASP.NET Core.

Blazor opcje koncentratora

Skonfiguruj MapBlazorHub opcje sterowania HttpConnectionDispatcherOptions koncentratorem Blazor . Wyświetl wartości domyślne opcji dyspozytora połączeń koncentratora w źródle referencyjnym. Symbol {OPTION} zastępczy reprezentuje opcję, a {VALUE} symbol zastępczy jest wartością.

Uwaga

Linki dokumentacji do źródła referencyjnego platformy .NET zwykle ładują domyślną gałąź repozytorium, która odzwierciedla bieżące programowanie dla następnej wersji platformy .NET. Aby wybrać tag dla określonej wersji, użyj listy rozwijanej Przełącz gałęzie lub tagi. Aby uzyskać więcej informacji, zobacz Jak wybrać tag wersji kodu źródłowego platformy ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Umieść wywołanie metody po app.MapBlazorHub wywołaniu metody app.MapRazorComponents w pliku aplikacji Program :

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

Podaj opcje app.MapBlazorHub w pliku aplikacji Program :

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

Podaj opcje w app.MapBlazorHub konfiguracji routingu punktu końcowego:

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

Maksymalny rozmiar komunikatu odbioru

Ta sekcja dotyczy tylko projektów implementujących SignalRprogram .

Maksymalny rozmiar komunikatu przychodzącego SignalR dozwolony dla metod centrum jest ograniczony ( HubOptions.MaximumReceiveMessageSize domyślnie: 32 KB). SignalR komunikaty większe niż MaximumReceiveMessageSize zgłaszają błąd. Struktura nie nakłada limitu rozmiaru komunikatu SignalR z centrum na klienta.

Jeśli SignalR rejestrowanie nie jest ustawione na debugowanie lub śledzenie, w konsoli narzędzi deweloperskich przeglądarki pojawia się tylko błąd rozmiaru komunikatu:

Błąd: Połączenie ion rozłączony z błędem "Błąd: Serwer zwrócił błąd podczas zamykania: Połączenie ion został zamknięty z powodu błędu.

Gdy SignalR rejestrowanie po stronie serwera jest ustawione na debugowanie lub śledzenie, rejestrowanie po stronie serwera wyświetla InvalidDataException błąd rozmiaru komunikatu.

appsettings.Development.json:

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

Błąd:

System.IO.InvalidDataException: przekroczono maksymalny rozmiar komunikatu 32768B. Rozmiar komunikatu można skonfigurować w obszarze AddHubOptions.

Jedno podejście polega na zwiększeniu limitu przez ustawienie MaximumReceiveMessageSize w Program pliku. Poniższy przykład ustawia maksymalny rozmiar komunikatu odbioru na 64 KB:

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

Zwiększenie limitu rozmiaru SignalR komunikatów przychodzących wiąże się z kosztem wymagania większej ilości zasobów serwera i zwiększa ryzyko ataków typu "odmowa usługi" (DoS). Ponadto odczytywanie dużej ilości zawartości w pamięci jako ciągów lub tablic bajtów może również spowodować alokacje, które działają źle z modułem odśmiecenia pamięci, co powoduje dodatkowe kary za wydajność.

Lepszym rozwiązaniem do odczytywania dużych ładunków jest wysłanie zawartości w mniejszych fragmentach i przetworzenie ładunku jako Stream. Może to być używane podczas odczytywania dużych ładunków języka JavaScript (JS) w trybie ON lub jeśli JS dane międzyoperacyjności JSsą dostępne jako nieprzetworzone bajty. Przykład przedstawiający wysyłanie dużych ładunków binarnych w aplikacjach po stronie serwera, które używają technik podobnych do składnika, zobacz przykładową aplikację Binary Submit iInputLargeTextAreaBlazor Przykładowy składnik.InputFile

Uwaga

Linki dokumentacji do źródła referencyjnego platformy .NET zwykle ładują domyślną gałąź repozytorium, która odzwierciedla bieżące programowanie dla następnej wersji platformy .NET. Aby wybrać tag dla określonej wersji, użyj listy rozwijanej Przełącz gałęzie lub tagi. Aby uzyskać więcej informacji, zobacz Jak wybrać tag wersji kodu źródłowego platformy ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Formularze, które przetwarzają duże ładunki, mogą również bezpośrednio używać międzyoperacyjności SignalR przesyłania strumieniowego JS . Aby uzyskać więcej informacji, zobacz Wywoływanie metod platformy .NET z funkcji Języka JavaScript w programie ASP.NET Core Blazor. Aby zapoznać się z przykładem formularzy przesyłających strumieniowo dane do serwera, zobacz Rozwiązywanie problemów z formularzami <textarea>ASP.NET CoreBlazor.

Jedno podejście polega na zwiększeniu limitu przez ustawienie MaximumReceiveMessageSize w Program pliku. Poniższy przykład ustawia maksymalny rozmiar komunikatu odbioru na 64 KB:

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

Zwiększenie limitu rozmiaru SignalR komunikatów przychodzących wiąże się z kosztem wymagania większej ilości zasobów serwera i zwiększa ryzyko ataków typu "odmowa usługi" (DoS). Ponadto odczytywanie dużej ilości zawartości w pamięci jako ciągów lub tablic bajtów może również spowodować alokacje, które działają źle z modułem odśmiecenia pamięci, co powoduje dodatkowe kary za wydajność.

Lepszym rozwiązaniem do odczytywania dużych ładunków jest wysłanie zawartości w mniejszych fragmentach i przetworzenie ładunku jako Stream. Może to być używane podczas odczytywania dużych ładunków języka JavaScript (JS) w trybie ON lub jeśli JS dane międzyoperacyjności JSsą dostępne jako nieprzetworzone bajty. Aby zapoznać się z przykładem wysyłania dużych ładunków binarnych w Blazor Server programie, które używają technik podobnych do InputFile składnika, zobacz przykładową aplikację Binary Submit i BlazorInputLargeTextArea przykładowy składnik.

Uwaga

Linki dokumentacji do źródła referencyjnego platformy .NET zwykle ładują domyślną gałąź repozytorium, która odzwierciedla bieżące programowanie dla następnej wersji platformy .NET. Aby wybrać tag dla określonej wersji, użyj listy rozwijanej Przełącz gałęzie lub tagi. Aby uzyskać więcej informacji, zobacz Jak wybrać tag wersji kodu źródłowego platformy ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Formularze, które przetwarzają duże ładunki, mogą również bezpośrednio używać międzyoperacyjności SignalR przesyłania strumieniowego JS . Aby uzyskać więcej informacji, zobacz Wywoływanie metod platformy .NET z funkcji Języka JavaScript w programie ASP.NET Core Blazor. Aby zapoznać się z przykładem formularzy przesyłających strumieniowo dane w Blazor Server aplikacji, zobacz Rozwiązywanie problemów z formularzami <textarea>ASP.NET CoreBlazor.

Zwiększ limit, ustawiając wartość w pliku MaximumReceiveMessageSizeStartup.ConfigureServices:

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

Zwiększenie limitu rozmiaru SignalR komunikatów przychodzących wiąże się z kosztem wymagania większej ilości zasobów serwera i zwiększa ryzyko ataków typu "odmowa usługi" (DoS). Ponadto odczytywanie dużej ilości zawartości w pamięci jako ciągów lub tablic bajtów może również spowodować alokacje, które działają źle z modułem odśmiecenia pamięci, co powoduje dodatkowe kary za wydajność.

Podczas tworzenia kodu, który przesyła dużą ilość danych, należy wziąć pod uwagę następujące wskazówki:

  • Podziel dane na mniejsze elementy i wysyłaj segmenty danych sekwencyjnie do momentu odebrania wszystkich danych przez serwer.
  • Nie przydzielaj dużych obiektów w JS kodzie i C#.
  • Nie blokuj głównego wątku interfejsu użytkownika przez długi czas podczas wysyłania lub odbierania danych.
  • Bezpłatna ilość zużytej pamięci po zakończeniu lub anulowaniu procesu.
  • Wymuś następujące dodatkowe wymagania dotyczące zabezpieczeń:
    • Zadeklaruj maksymalny rozmiar pliku lub danych, który można przekazać.
    • Zadeklaruj minimalną szybkość przekazywania od klienta do serwera.
  • Po odebraniu danych przez serwer dane mogą być następujące:
    • Tymczasowo przechowywane w buforze pamięci do momentu zebrania wszystkich segmentów.
    • Zużytych natychmiast. Na przykład dane mogą być przechowywane natychmiast w bazie danych lub zapisywane na dysku w miarę odbierania poszczególnych segmentów.

Blazor Konfiguracja trasy punktu końcowego koncentratora po stronie serwera

W pliku wywołaj Program metodę MapBlazorHub , aby zamapować BlazorHub element na domyślną ścieżkę aplikacji. Skrypt Blazor (blazor.*.js) automatycznie wskazuje punkt końcowy utworzony przez MapBlazorHubprogram .

Emocje stanu połączenia po stronie serwera w interfejsie użytkownika

Gdy klient wykryje, że połączenie zostało utracone, domyślny interfejs użytkownika jest wyświetlany użytkownikowi podczas próby ponownego nawiązania połączenia przez klienta. Jeśli ponowne nawiązanie połączenia nie powiedzie się, użytkownik otrzyma opcję ponawiania próby.

Aby dostosować interfejs użytkownika, zdefiniuj pojedynczy element za pomocą elementu idcomponents-reconnect-modal. Poniższy przykład umieszcza element w składniku App .

App.razor:

Aby dostosować interfejs użytkownika, zdefiniuj pojedynczy element za pomocą elementu idcomponents-reconnect-modal. Poniższy przykład umieszcza element na stronie hosta.

Pages/_Host.cshtml:

Aby dostosować interfejs użytkownika, zdefiniuj pojedynczy element za pomocą elementu idcomponents-reconnect-modal. Poniższy przykład umieszcza element na stronie układu.

Pages/_Layout.cshtml:

Aby dostosować interfejs użytkownika, zdefiniuj pojedynczy element za pomocą elementu idcomponents-reconnect-modal. Poniższy przykład umieszcza element na stronie hosta.

Pages/_Host.cshtml:

<div id="components-reconnect-modal">
    There was a problem with the connection!
</div>

Uwaga

Jeśli aplikacja renderuje więcej niż jeden element z elementem idcomponents-reconnect-modal , tylko pierwszy renderowany element otrzymuje zmiany klasy CSS w celu wyświetlenia lub ukrycia elementu.

Dodaj następujące style CSS do arkusza stylów witryny.

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;
}

W poniższej tabeli opisano klasy CSS zastosowane do components-reconnect-modal elementu przez platformę Blazor .

Klasa CSS Wskazuje...
components-reconnect-show Utracone połączenie. Klient próbuje ponownie nawiązać połączenie. Pokaż modalne.
components-reconnect-hide Aktywne połączenie zostanie ponownie nawiązane z serwerem. Ukryj modalne.
components-reconnect-failed Ponowne nawiązywanie połączenia nie powiodło się, prawdopodobnie z powodu awarii sieci. Aby spróbować ponownie nawiązać połączenie, wywołaj metodę window.Blazor.reconnect() w języku JavaScript.
components-reconnect-rejected Ponowne połączenie odrzucone. Serwer został osiągnięty, ale odmówił połączenia, a stan użytkownika na serwerze zostanie utracony. Aby ponownie załadować aplikację, wywołaj metodę location.reload() w języku JavaScript. Ten stan połączenia może spowodować, że:
  • Występuje awaria obwodu po stronie serwera.
  • Klient jest odłączony wystarczająco długo, aby serwer porzucił stan użytkownika. Wystąpienia składników użytkownika są usuwane.
  • Serwer jest uruchamiany ponownie lub proces roboczy aplikacji jest odzyskiwane.

Dostosuj opóźnienie przed wyświetleniem wyświetlania ponownego połączenia, ustawiając transition-delay właściwość w arkuszu CSS witryny dla elementu modalnego. W poniższym przykładzie ustawiono opóźnienie przejścia z 500 ms (wartość domyślna) na 1000 ms (1 sekunda).

wwwroot/app.css:

wwwroot/css/site.css:

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

Aby wyświetlić bieżącą próbę ponownego nawiązania połączenia, zdefiniuj element z wartością idcomponents-reconnect-current-attempt. Aby wyświetlić maksymalną liczbę ponownych prób ponownego połączenia, zdefiniuj element z wartością idcomponents-reconnect-max-retries. Poniższy przykład umieszcza te elementy wewnątrz elementu ponowić próbę połączenia modalne po poprzednim przykładzie.

<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>

Gdy pojawi się modalne ponowne połączenie niestandardowe, renderuje zawartość podobną do następującej na podstawie poprzedniego kodu:

There was a problem with the connection! (Current reconnect attempt: 3 / 8)

Renderowanie po stronie serwera

Domyślnie składniki są wstępnie obsługiwane na serwerze przed nawiązaniem połączenia klienta z serwerem. Aby uzyskać więcej informacji, zobacz Prerender ASP.NET Core components (Składniki prerender ASP.NET CoreRazor).

Domyślnie składniki są wstępnie obsługiwane na serwerze przed nawiązaniem połączenia klienta z serwerem. Aby uzyskać więcej informacji, zobacz Pomocnik tagów składników w programie ASP.NET Core.

Monitorowanie aktywności obwodu po stronie serwera

Monitoruj aktywność obwodu przychodzącego CreateInboundActivityHandler przy użyciu metody w pliku CircuitHandler. Działanie obwodu przychodzącego to wszelkie działania wysyłane z przeglądarki do serwera, takie jak zdarzenia interfejsu użytkownika lub JavaScript-to-.NET wywołania międzyoperacowe.

Można na przykład użyć programu obsługi działań obwodu, aby wykryć, czy klient jest w stanie bezczynności i zarejestrować jego identyfikator obwodu (Circuit.Id):

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;
    }
}

Zarejestruj usługę Program w pliku. Poniższy przykład konfiguruje domyślny limit czasu bezczynności od pięciu minut do pięciu sekund w celu przetestowania poprzedniej IdleCircuitHandler implementacji:

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

Programy obsługi działań obwodu zapewniają również podejście do uzyskiwania dostępu do usług o określonym Blazor zakresie z innychBlazor zakresów iniekcji zależności (DI). Aby uzyskać więcej informacji i przykładów, zobacz:

Blazor Uruchamiania

Skonfiguruj ręczne uruchamianie obwodu Blazor aplikacji w App.razor pliku Blazor aplikacji SignalR internetowej:

Skonfiguruj ręczne uruchamianie obwodu Blazor aplikacji SignalR w Pages/_Host.cshtml pliku (Blazor Server):

Skonfiguruj ręczne uruchamianie obwodu Blazor aplikacji SignalR w Pages/_Layout.cshtml pliku (Blazor Server):

Skonfiguruj ręczne uruchamianie obwodu Blazor aplikacji SignalR w Pages/_Host.cshtml pliku (Blazor Server):

  • autostart="false" Dodaj atrybut do tagu <script> skryptublazor.*.js.
  • Umieść skrypt wywołujący Blazor.start() po załadowaniu skryptu Blazor i wewnątrz tagu zamykającego </body> .

Gdy autostart funkcja jest wyłączona, każdy aspekt aplikacji, który nie zależy od obwodu, działa normalnie. Na przykład routing po stronie klienta działa. Jednak każdy aspekt, który zależy od obwodu, nie działa, dopóki Blazor.start() nie zostanie wywołany. Zachowanie aplikacji jest nieprzewidywalne bez ustalonego obwodu. Na przykład metody składników nie mogą być wykonywane, gdy obwód jest odłączony.

Aby uzyskać więcej informacji, w tym sposób inicjowania Blazor , gdy dokument jest gotowy i jak utworzyć łańcuch do elementu JS Promise, zobacz ASP.NET Core Blazor start.

Konfigurowanie SignalR limitów czasu i zachowania aktywności na kliencie

Skonfiguruj następujące wartości dla klienta:

  • withServerTimeout: konfiguruje limit czasu serwera w milisekundach. Jeśli ten limit czasu upłynie bez odbierania komunikatów z serwera, połączenie zostanie zakończone z powodu błędu. Domyślna wartość limitu czasu to 30 sekund. Limit czasu serwera powinien być co najmniej dwukrotnie większy niż wartość przypisana do interwału Keep-Alive (withKeepAliveInterval).
  • withKeepAliveInterval: konfiguruje interwał Keep-Alive w milisekundach (domyślny interwał, w którym ma być wysyłana polecenie ping do serwera). To ustawienie umożliwia serwerowi wykrywanie twardych rozłączeń, takich jak odłączanie komputera od sieci przez klienta. Polecenie ping występuje co najwyżej w przypadku ping serwera. Jeśli serwer wysyła polecenia ping co pięć sekund, przypisywanie wartości niższej niż 5000 (5 sekund) ping co pięć sekund. Wartość domyślna to 15 sekund. Interwał Keep-Alive powinien być mniejszy lub równy połowie wartości przypisanej do limitu czasu serwera (withServerTimeout).

Poniższy przykład dla App.razor pliku (Blazor Aplikacja internetowa) pokazuje przypisanie wartości domyślnych.

Blazor Aplikacja internetowa:

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

Poniższy przykład dla Pages/_Host.cshtml pliku (Blazor Serverwszystkie wersje z wyjątkiem ASP.NET Core na platformie .NET 6) lub Pages/_Layout.cshtml plik (Blazor ServerASP.NET Core na platformie .NET 6).

Blazor Server:

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

W poprzednim przykładzie {BLAZOR SCRIPT} symbol zastępczy to ścieżka skryptu Blazor i nazwa pliku. Aby uzyskać informacje o lokalizacji skryptu i ścieżce do użycia, zobacz ASP.NET Core project structure (Struktura projektu ASP.NET CoreBlazor).

Podczas tworzenia połączenia koncentratora w składniku ustaw ServerTimeout wartość (domyślną: 30 sekund) i KeepAliveInterval (domyślnie: 15 sekund) na .HubConnectionBuilder Ustaw wartość (domyślną HandshakeTimeout : 15 sekund) na skompilowanych HubConnectionelementach . W poniższym przykładzie pokazano przypisanie wartości domyślnych:

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();
}

Skonfiguruj następujące wartości dla klienta:

  • serverTimeoutInMilliseconds: limit czasu serwera w milisekundach. Jeśli ten limit czasu upłynie bez odbierania komunikatów z serwera, połączenie zostanie zakończone z powodu błędu. Domyślna wartość limitu czasu to 30 sekund. Limit czasu serwera powinien być co najmniej dwukrotnie większy niż wartość przypisana do interwału Keep-Alive (keepAliveIntervalInMilliseconds).
  • keepAliveIntervalInMilliseconds: domyślny interwał ping do serwera. To ustawienie umożliwia serwerowi wykrywanie twardych rozłączeń, takich jak odłączanie komputera od sieci przez klienta. Polecenie ping występuje co najwyżej w przypadku ping serwera. Jeśli serwer wysyła polecenia ping co pięć sekund, przypisywanie wartości niższej niż 5000 (5 sekund) ping co pięć sekund. Wartość domyślna to 15 sekund. Interwał Keep-Alive powinien być mniejszy lub równy połowie wartości przypisanej do limitu czasu serwera (serverTimeoutInMilliseconds).

Poniższy przykład dla Pages/_Host.cshtml pliku (Blazor Serverwszystkie wersje z wyjątkiem ASP.NET Core na platformie .NET 6) lub Pages/_Layout.cshtml plik (Blazor ServerASP.NET Core na platformie .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>

W poprzednim przykładzie {BLAZOR SCRIPT} symbol zastępczy to ścieżka skryptu Blazor i nazwa pliku. Aby uzyskać informacje o lokalizacji skryptu i ścieżce do użycia, zobacz ASP.NET Core project structure (Struktura projektu ASP.NET CoreBlazor).

Podczas tworzenia połączenia koncentratora w składniku ustaw ServerTimeout wartość (domyślna: 30 sekund), HandshakeTimeout (wartość domyślna: 15 sekund) i KeepAliveInterval (wartość domyślna: 15 sekund) na skompilowanych HubConnectionelementach . W poniższym przykładzie pokazano przypisanie wartości domyślnych:

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();
}

Podczas zmieniania wartości limitu czasu serwera (ServerTimeout) lub interwału Keep-Alive (KeepAliveInterval):

  • Limit czasu serwera powinien być co najmniej dwukrotnie większy niż wartość przypisana do interwału Keep-Alive.
  • Interwał Keep-Alive powinien być mniejszy lub równy połowie wartości przypisanej do limitu czasu serwera.

Aby uzyskać więcej informacji, zobacz sekcje Global deployment and connection failures (Globalne błędy wdrażania i połączeń) w następujących artykułach:

Modyfikowanie programu obsługi ponownego łączenia po stronie serwera

Zdarzenia połączenia obwodu programu obsługi ponownego połączenia można modyfikować pod kątem zachowań niestandardowych, takich jak:

  • Aby powiadomić użytkownika o usunięciu połączenia.
  • Aby wykonać rejestrowanie (z klienta), gdy obwód jest połączony.

Aby zmodyfikować zdarzenia połączenia, zarejestruj wywołania zwrotne dla następujących zmian połączenia:

  • Porzucone połączenia używają polecenia onConnectionDown.
  • Nawiązane/ponownie nawiązane połączenia używają polecenia onConnectionUp.

Należy określić oba onConnectionDown elementy i onConnectionUp .

Blazor Aplikacja internetowa:

<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>

W poprzednim przykładzie {BLAZOR SCRIPT} symbol zastępczy to ścieżka skryptu Blazor i nazwa pliku. Aby uzyskać informacje o lokalizacji skryptu i ścieżce do użycia, zobacz ASP.NET Core project structure (Struktura projektu ASP.NET CoreBlazor).

Automatyczne odświeżanie strony w przypadku niepowodzenia ponownego nawiązania połączenia po stronie serwera

Domyślne zachowanie ponownego nawiązywania połączenia wymaga od użytkownika ręcznego wykonania akcji w celu odświeżenia strony po niepomyślnie nawiązaniu połączenia. Można jednak użyć niestandardowego programu obsługi ponownego łączenia, aby automatycznie odświeżyć stronę:

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>

W poprzednim przykładzie {BLAZOR SCRIPT} symbol zastępczy to ścieżka skryptu Blazor i nazwa pliku. Aby uzyskać informacje o lokalizacji skryptu i ścieżce do użycia, zobacz ASP.NET Core project structure (Struktura projektu ASP.NET CoreBlazor).

Utwórz następujący wwwroot/boot.js plik.

Blazor Aplikacja internetowa:

(() => {
  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;
      }
    }
  });
})();

Aby uzyskać więcej informacji na temat uruchamiania platformy Blazor, zobacz Uruchamianie platformy ASP.NET Core Blazor.

Dostosowywanie liczby ponownych prób i interwału ponownego połączenia po stronie serwera

Aby dostosować liczbę ponownych prób połączenia i interwał, ustaw liczbę ponownych prób (maxRetries) i okres w milisekundach dozwolonych dla każdej próby ponawiania próby (retryIntervalMilliseconds).

Blazor Aplikacja internetowa:

<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>

W poprzednim przykładzie {BLAZOR SCRIPT} symbol zastępczy to ścieżka skryptu Blazor i nazwa pliku. Aby uzyskać informacje o lokalizacji skryptu i ścieżce do użycia, zobacz ASP.NET Core project structure (Struktura projektu ASP.NET CoreBlazor).

Aby uzyskać więcej informacji na temat uruchamiania platformy Blazor, zobacz Uruchamianie platformy ASP.NET Core Blazor.

Kontrolka po wyświetleniu interfejsu użytkownika ponownego połączenia

Kontrolowanie, kiedy interfejs użytkownika ponownego łączenia może być przydatny w następujących sytuacjach:

  • Wdrożona aplikacja często wyświetla interfejs użytkownika ponownego nawiązywania połączenia z powodu przekroczenia limitu czasu ping spowodowanych przez sieć wewnętrzną lub opóźnienie internetowe i chcesz zwiększyć opóźnienie.
  • Aplikacja powinna zgłaszać użytkownikom, że połączenie spadło wcześniej i chcesz skrócić opóźnienie.

Czas wyświetlania interfejsu użytkownika ponownego nawiązywania połączenia ma wpływ na dostosowanie interwału Keep-Alive i limitów czasu na kliencie. Jednak zmiana ustawienia może wymagać zmian innych ustawień Keep-Alive, limitu czasu i uzgadniania.

Zgodnie z ogólnymi zaleceniami dotyczącymi poniższych wskazówek:

  • Interwał Keep-Alive powinien być zgodny z konfiguracjami klienta i serwera.
  • Limity czasu powinny mieć co najmniej dwukrotnie wartość przypisaną do interwału Keep-Alive.

Konfiguracja serwera

Ustaw następujące ustawienia:

  • ClientTimeoutInterval (ustawienie domyślne: 30 sekund): klienci przedziału czasu muszą wysłać komunikat, zanim serwer zamknie połączenie.
  • HandshakeTimeout (ustawienie domyślne: 15 sekund): interwał używany przez serwer do przekroczenia limitu czasu przychodzących żądań uzgadniania przez klientów.
  • KeepAliveInterval (wartość domyślna: 15 sekund): interwał używany przez serwer do wysyłania utrzymywania aktywności poleceń ping do połączonych klientów. Należy pamiętać, że istnieje również ustawienie interwału Keep-Alive na kliencie, które powinno być zgodne z wartością serwera.

Element ClientTimeoutInterval i HandshakeTimeout można zwiększyć, a element KeepAliveInterval może pozostać taki sam. Należy pamiętać, że jeśli zmienisz wartości, upewnij się, że limity czasu są co najmniej dwukrotnie równe interwałowi Keep-Alive i że interwał Keep-Alive jest zgodny między serwerem a klientem. Aby uzyskać więcej informacji, zobacz sekcję Konfigurowanie SignalR limitów czasu i funkcji Keep-Alive na kliencie .

W poniższym przykładzie:

  • Wartość ClientTimeoutInterval jest zwiększana do 60 sekund (wartość domyślna: 30 sekund).
  • Wartość HandshakeTimeout jest zwiększana do 30 sekund (wartość domyślna: 15 sekund).
  • Parametr KeepAliveInterval nie jest ustawiony w kodzie dewelopera i używa jego wartości domyślnej 15 sekund. Zmniejszenie wartości interwału Keep-Alive zwiększa częstotliwość wysyłania poleceń ping do komunikacji, co zwiększa obciążenie aplikacji, serwera i sieci. Należy zachować ostrożność, aby uniknąć wprowadzania niskiej wydajności podczas obniżania interwału Keep-Alive.

Blazor Aplikacja internetowa (.NET 8 lub nowsza Program ) w pliku projektu serwera:

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

Blazor ServerProgram w pliku:

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

Aby uzyskać więcej informacji, zobacz sekcję Opcje obsługi obwodu po stronie serwera.

Konfiguracja klientów

Ustaw następujące ustawienia:

  • withServerTimeout (wartość domyślna: 30 sekund): konfiguruje limit czasu serwera określony w milisekundach dla połączenia koncentratora obwodu.
  • withKeepAliveInterval (wartość domyślna: 15 sekund): interwał określony w milisekundach, w którym połączenie wysyła komunikaty Keep-Alive.

Limit czasu serwera można zwiększyć, a interwał Keep-Alive może pozostać taki sam. Należy pamiętać, że jeśli zmienisz wartości, upewnij się, że limit czasu serwera jest co najmniej dwukrotnie większy niż wartość interwału Keep-Alive i że wartości interwału Keep-Alive są zgodne między serwerem a klientem. Aby uzyskać więcej informacji, zobacz sekcję Konfigurowanie SignalR limitów czasu i funkcji Keep-Alive na kliencie .

W poniższym przykładzie konfiguracji uruchamiania (lokalizacja skryptuBlazor) dla limitu czasu serwera jest używana niestandardowa wartość 60 sekund. Interwał Keep-Alive (withKeepAliveInterval) nie jest ustawiony i używa wartości domyślnej 15 sekund.

Blazor Aplikacja internetowa:

<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>

Podczas tworzenia połączenia koncentratora w składniku ustaw limit czasu serwera (WithServerTimeoutdomyślnie: 30 sekund) na .HubConnectionBuilder Ustaw wartość (domyślną HandshakeTimeout : 15 sekund) na skompilowanych HubConnectionelementach . Upewnij się, że limity czasu są co najmniej dwukrotnie równe interwałowi Keep-Alive (WithKeepAliveInterval/KeepAliveInterval) i że wartość Keep-Alive jest zgodna między serwerem a klientem.

Poniższy przykład jest oparty na składniku Index w samouczku z samouczkiemSignalRBlazor. Limit czasu serwera jest zwiększany do 60 sekund, a limit czasu uzgadniania jest zwiększany do 30 sekund. Interwał Keep-Alive nie jest ustawiony i używa wartości domyślnej 15 sekund.

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();
}

Ustaw następujące ustawienia:

  • serverTimeoutInMilliseconds (wartość domyślna: 30 sekund): konfiguruje limit czasu serwera określony w milisekundach dla połączenia koncentratora obwodu.
  • keepAliveIntervalInMilliseconds (wartość domyślna: 15 sekund): interwał określony w milisekundach, w którym połączenie wysyła komunikaty Keep-Alive.

Limit czasu serwera można zwiększyć, a interwał Keep-Alive może pozostać taki sam. Należy pamiętać, że jeśli zmienisz wartości, upewnij się, że limit czasu serwera jest co najmniej dwukrotnie większy niż wartość interwału Keep-Alive i że wartości interwału Keep-Alive są zgodne między serwerem a klientem. Aby uzyskać więcej informacji, zobacz sekcję Konfigurowanie SignalR limitów czasu i funkcji Keep-Alive na kliencie .

W poniższym przykładzie konfiguracji uruchamiania (lokalizacja skryptuBlazor) dla limitu czasu serwera jest używana niestandardowa wartość 60 sekund. Interwał Keep-Alive (keepAliveIntervalInMilliseconds) nie jest ustawiony i używa wartości domyślnej 15 sekund.

W pliku 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>

Podczas tworzenia połączenia koncentratora w składniku ustaw ServerTimeout wartość (domyślną: 30 sekund) i HandshakeTimeout (wartość domyślna: 15 sekund) na skompilowanych HubConnectionelementach . Upewnij się, że limity czasu są co najmniej dwukrotnie równe interwałowi Keep-Alive. Upewnij się, że interwał Keep-Alive jest zgodny między serwerem a klientem.

Poniższy przykład jest oparty na składniku Index w samouczku z samouczkiemSignalRBlazor. Wartość ServerTimeout jest zwiększana do 60 sekund i HandshakeTimeout zwiększa się do 30 sekund. Interwał Keep-Alive (KeepAliveInterval) nie jest ustawiony i używa wartości domyślnej 15 sekund.

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();
}

Blazor Odłącz obwód od klienta

Domyślnie Blazor obwód jest rozłączany po wyzwoleniu unload zdarzenia strony. Aby rozłączyć obwód dla innych scenariuszy na kliencie, należy wywołać Blazor.disconnect w odpowiedniej procedurze obsługi zdarzeń. W poniższym przykładzie obwód jest odłączony, gdy strona jest ukryta (pagehide zdarzenie):

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

Aby uzyskać więcej informacji na temat uruchamiania platformy Blazor, zobacz Uruchamianie platformy ASP.NET Core Blazor.

Procedura obsługi obwodu po stronie serwera

Można zdefiniować procedurę obsługi obwodu, która umożliwia uruchamianie kodu na zmianach stanu obwodu użytkownika. Procedura obsługi obwodów jest implementowana przez wyprowadzanie CircuitHandler i rejestrowanie klasy w kontenerze usługi aplikacji. Poniższy przykład procedury obsługi obwodów śledzi otwarte SignalR połączenia.

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;
}

Programy obsługi obwodów są rejestrowane przy użyciu di. Wystąpienia o określonym zakresie są tworzone na wystąpienie obwodu. TrackingCircuitHandler Korzystając z powyższego przykładu, jest tworzona pojedyncza usługa, ponieważ stan wszystkich obwodów musi być śledzony.

W pliku Program:

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

W Startup.ConfigureServices pliku :Startup.cs

services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();

Jeśli metody niestandardowego programu obsługi obwodu zgłaszają nieobsługiwany wyjątek, wyjątek jest krytyczny dla obwodu. Aby tolerować wyjątki w kodzie programu obsługi lub wywoływanych metodach, opakuj kod w co najmniej jednej try-catch instrukcji z obsługą błędów i rejestrowaniem.

Gdy obwód kończy się, ponieważ użytkownik rozłączył się, a struktura czyści stan obwodu, struktura usuwa zakres di obwodu. Usuwanie zakresu usuwa wszystkie usługi DI o zakresie obwodu, które implementują System.IDisposable. Jeśli jakakolwiek usługa DI zgłasza nieobsługiwany wyjątek podczas usuwania, struktura rejestruje wyjątek. Aby uzyskać więcej informacji, zobacz ASP.NET Core dependency injection (Wstrzykiwanie zależności ASP.NET CoreBlazor).

Procedura obsługi obwodu po stronie serwera w celu przechwytywania użytkowników dla usług niestandardowych

Użyj elementu , CircuitHandler aby przechwycić użytkownika z AuthenticationStateProvider elementu i ustawić tego użytkownika w usłudze. Aby uzyskać więcej informacji i przykładowy kod, zobacz Scenariusze zabezpieczeń po stronie serwera ASP.NET CoreBlazor.

Zamykanie obwodów, gdy nie ma pozostałych składników programu Interactive Server

Składniki interaktywnego serwera obsługują zdarzenia internetowego interfejsu użytkownika przy użyciu połączenia w czasie rzeczywistym z przeglądarką nazywaną obwodem. Obwód i skojarzony z nim stan są tworzone, gdy jest renderowany główny składnik interactive server. Obwód jest zamykany, gdy na stronie nie ma żadnych pozostałych składników serwera interakcyjnego, co zwalnia zasoby serwera.

IHttpContextAccessor/HttpContext w Razor składnikach

IHttpContextAccessor należy unikać renderowania interakcyjnego, ponieważ nie ma prawidłowej HttpContext dostępności.

IHttpContextAccessor Może służyć do składników, które są statycznie renderowane na serwerze. Zalecamy jednak unikanie go, jeśli to możliwe.

HttpContextMoże być używany jako parametr kaskadowy tylko w statycznie renderowanych składnikach głównych dla zadań ogólnych, takich jak inspekcja i modyfikowanie nagłówków lub innych właściwości w składniku App (Components/App.razor). Wartość jest zawsze null dla renderowania interakcyjnego.

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

W przypadku scenariuszy, w których HttpContext element jest wymagany w składnikach interaktywnych, zalecamy przepływ danych za pośrednictwem stanu trwałego składnika z serwera. Aby uzyskać więcej informacji, zobacz Scenariusze zabezpieczeń po stronie serwera ASP.NET CoreBlazor.

Nie używaj IHttpContextAccessor/HttpContext bezpośrednio ani pośrednio składników Razor aplikacji po stronie Blazor serwera. Blazor aplikacje działają poza kontekstem potoku ASP.NET Core. Nie HttpContext ma gwarancji, że element jest dostępny w programie IHttpContextAccessori HttpContext nie ma gwarancji, że przechowuje kontekst, w ramach którego uruchomiono aplikację Blazor .

Zalecaną metodą przekazywania stanu żądania do Blazor aplikacji są parametry składnika głównego podczas początkowego renderowania aplikacji. Alternatywnie aplikacja może skopiować dane do usługi o określonym zakresie w zdarzeniu cyklu życia inicjowania składnika głównego do użycia w całej aplikacji. Aby uzyskać więcej informacji, zobacz Scenariusze zabezpieczeń po stronie serwera ASP.NET CoreBlazor.

Krytycznym aspektem zabezpieczeń po stronie Blazor serwera jest to, że użytkownik dołączony do danego obwodu może zostać zaktualizowany w pewnym momencie po ustanowieniu obwoduBlazor, ale IHttpContextAccessornie został zaktualizowany. Aby uzyskać więcej informacji na temat rozwiązywania tej sytuacji z usługami niestandardowymi, zobacz Scenariusze zabezpieczeń po stronie serwera ASP.NET CoreBlazor.

Dodatkowe zasoby po stronie serwera