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ą, zobacz wersję tego artykułu platformy .NET 9.
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ą, zobacz wersję tego artykułu platformy .NET 9.
W tym artykule wyjaśniono, jak konfigurować połączenia w SignalR aplikacjach i zarządzać nimiBlazor.
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.
Usługa platformy Azure SignalR z stanowym ponownym połączeniem
Usługa Azure SignalR Service z zestawem SDK w wersji 1.26.1 lub nowsza obsługuje SignalR stanowe ponowne łączenie (WithStatefulReconnect).
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. DisableWebSocketCompression (ustawienie domyślne:
false
) steruje kompresją protokołu WebSocket.frame-ancestors
Przyję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ść ContentSecurityFrameAncestorsPolicy 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.
Służy ConfigureWebSocketAcceptContext do konfigurowania WebSocketAcceptContext połączeń protokołu websocket używanych przez składniki serwera. Domyślnie są stosowane zasady, które umożliwiają kompresję i ustawiają dostawcę CSP dla elementów podrzędnych ramek zdefiniowanych w ContentSecurityFrameAncestorsPolicy programie.
Przykłady użycia:
Wyłącz kompresję, ustawiając wartość DisableWebSocketCompressiontrue
, co zmniejsza lukę w zabezpieczeniach aplikacji do ataku , ale może spowodować zmniejszenie wydajności:
builder.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(o => o.DisableWebSocketCompression = true)
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ść ContentSecurityFrameAncestorsPolicynull
. 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
'none'
'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 Blazor serwera ASP.NET Core. 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 pliki cookie lub nagłówki uwierzytelniania HTTP.
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 SignalR ASP.NET Core).
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 Razor prerender ASP.NET Core).
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ć Blazorlimit 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.
- Interfejs użytkownika ponownego nawiązywania połączenia na kliencie jest wyświetlany, gdy obwód ulegnie awarii. 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 limitSignalR OSTRZEŻENIE: Zwiększenie limitu może zwiększyć ryzyko ataków typu "odmowa usługi" (DoS).
Dodatkowe zasoby po stronie klienta
- Zabezpieczanie SignalR koncentratora
- Omówienie platformy ASP.NET Core SignalR
- Konfiguracja SignalR na platformie ASP.NET Core
-
dotnet/blazor-samples
(jak pobrać)
Używanie koligacji sesji (sesji lepkich) na potrzeby hostingu farmy internetowej po stronie serwera
Gdy jest używany więcej niż jeden serwer zaplecza, aplikacja musi zaimplementować koligację sesji, nazywaną również sesjami sticky. Koligacja sesji gwarantuje, że obwód klienta ponownie łączy się z tym samym serwerem, jeśli połączenie zostanie przerwane, co jest ważne, ponieważ stan klienta jest przechowywany tylko w pamięci serwera, który po raz pierwszy ustanowił obwód klienta.
Następujący błąd jest zgłaszany przez aplikację, która nie włączyła koligacji sesji w farmie internetowej:
Uncaught (in promise) Error: Invocation canceled due to the underlying connection being closed.
Aby uzyskać więcej informacji na temat koligacji sesji z hostingiem usługi aplikacja systemu Azure, zobacz Blazor po stronie serwera ASP.NET Core.
Usługa platformy Azure SignalR
Opcjonalna SignalR platformy Azure działa w połączeniu z centrum aplikacji SignalR w celu skalowania aplikacji w górę aplikacji po stronie serwera do dużej liczby współbieżnych połączeń. Ponadto globalne zasięg usługi i centra danych o wysokiej wydajności znacznie pomagają zmniejszyć opóźnienia ze względu na lokalizację geograficzną.
Usługa nie jest wymagana w przypadku Blazor aplikacji hostowanych w usłudze aplikacja systemu Azure Lub Azure Container Apps, ale może być przydatna w innych środowiskach hostingu:
- Aby ułatwić skalowanie połączeń w poziomie.
- Obsługa dystrybucji globalnej.
Aby uzyskać więcej informacji, zobacz Blazor po stronie 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 HubConnectionContextOptions.AddHubOptions Wyświetl wartości domyślne opcji kontekstu połączenia centrum w źródle referencyjnym. Opisy opcji w SignalR dokumentacji można znaleźć SignalR ASP.NET Core). 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).
Blazor wartość jest ustawiona na MaximumParallelInvocationsPerClient wartość 1, która jest wartością domyślną. Aby uzyskać więcej informacji, zobacz MaximumParallelInvocationsPerClient > 1 przerywa przekazywanie plików w Blazor Server trybie (dotnet/aspnetcore
#53951).
Aby uzyskać informacje na temat zarządzania pamięcią, zobacz Blazor po stronie 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};
});
Konfigurowanie koncentratora używanego przez AddInteractiveServerRenderMode program z niepowodzeniem z MapBlazorHub powodu błędu AmbiguousMatchException
:
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints.
Aby obejść problem dotyczący aplikacji przeznaczonych dla platformy .NET 8, nadaj niestandardowemu Blazor centrum wyższe pierwszeństwo przy użyciu WithOrder metody :
app.MapBlazorHub(options =>
{
options.CloseOnAuthenticationExpiration = true;
}).WithOrder(-1);
Aby uzyskać więcej informacji, zobacz następujące zasoby:
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 zostało rozłączone z powodu błędu "Błąd: Serwer zwrócił błąd podczas zamykania: połączenie zostało zamknięte 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 JSON międzyoperacyjności języka JavaScript (JS) lub jeśli JS dane międzyoperacyjne są 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 InputLargeTextArea
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 JSON międzyoperacyjności języka JavaScript (JS) lub jeśli JS dane międzyoperacyjne są 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 <textarea>
aplikacji, zobacz BlazorASP.NET Core.
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:
- Skorzystaj z natywnej obsługi międzyoperacyjności przesyłania strumieniowego JS , aby przesyłać dane większe niż limit rozmiaru komunikatów SignalR przychodzących:
- Ogólne porady:
- Nie przydzielaj dużych obiektów w JS kodzie i C#.
- 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.
- 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 .
Odzwierciedlanie stanu połączenia po stronie serwera w interfejsie użytkownika
Jeśli klient wykryje utracone połączenie z serwerem, domyślny interfejs użytkownika jest wyświetlany użytkownikowi, gdy klient próbuje ponownie nawiązać połączenie:
Jeśli ponowne nawiązanie połączenia nie powiedzie się, użytkownik zostanie poinstruowany, aby ponowić próbę lub ponownie załadować stronę:
Jeśli ponowne nawiązanie połączenia powiedzie się, stan użytkownika jest często utracony. Kod niestandardowy można dodać do dowolnego składnika w celu zapisania i ponownego załadowania stanu użytkownika w przypadku niepowodzeń połączenia. Aby uzyskać więcej informacji, zobacz Blazor ASP.NET Core.
Aby dostosować interfejs użytkownika, zdefiniuj pojedynczy element z elementem id
components-reconnect-modal
<body>
w zawartości elementu. Poniższy przykład umieszcza element w składniku App
.
App.razor
:
Aby dostosować interfejs użytkownika, zdefiniuj pojedynczy element z elementem id
components-reconnect-modal
<body>
w zawartości elementu. Poniższy przykład umieszcza element na stronie hosta.
Pages/_Host.cshtml
:
Aby dostosować interfejs użytkownika, zdefiniuj pojedynczy element z elementem id
components-reconnect-modal
<body>
w zawartości elementu. Poniższy przykład umieszcza element na stronie układu.
Pages/_Layout.cshtml
:
Aby dostosować interfejs użytkownika, zdefiniuj pojedynczy element z elementem id
components-reconnect-modal
<body>
w zawartości elementu. Poniższy przykład umieszcza element na stronie hosta.
Pages/_Host.cshtml
:
<div id="components-reconnect-modal">
Connection lost.<br>Attempting to reconnect...
</div>
Uwaga
Jeśli aplikacja renderuje więcej niż jeden element z elementem id
components-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;
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;
}
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:
|
Dostosuj opóźnienie przed wyświetleniem interfejsu użytkownika ponownego połączenia, ustawiając transition-delay
właściwość w pliku 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ą id
components-reconnect-current-attempt
. Aby wyświetlić maksymalną liczbę ponownych prób ponownego połączenia, zdefiniuj element z wartością id
components-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 następującą zawartość z licznikiem ponownego połączenia:
Wystąpił problem z połączeniem! (Bieżąca próba ponownego połączenia: 1/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 Razor prerender ASP.NET Core).
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 startup
Skonfiguruj ręczne uruchamianie obwodu Blazorw SignalRApp.razor
pliku Blazor Web App:
Skonfiguruj ręczne uruchamianie obwodu BlazorSignalR w Pages/_Host.cshtml
pliku (Blazor Server):
Skonfiguruj ręczne uruchamianie obwodu BlazorSignalR w Pages/_Layout.cshtml
pliku (Blazor Server):
Skonfiguruj ręczne uruchamianie obwodu BlazorSignalR 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 Web App) pokazuje przypisanie wartości domyślnych.
Blazor Web App:
<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 Blazor projektu ASP.NET Core).
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 Blazor projektu ASP.NET Core).
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:
- Hostowanie i wdrażanie aplikacji po stronie Blazor serwera ASP.NET Core
- Hostowanie i wdrażanie serwera ASP.NET Core Blazor WebAssembly
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 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>
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 Blazor projektu ASP.NET Core).
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 Blazor projektu ASP.NET Core).
Utwórz następujący wwwroot/boot.js
plik.
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;
}
}
});
})();
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 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>
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 Blazor projektu ASP.NET Core).
Gdy użytkownik przechodzi z powrotem do aplikacji z odłączonym obwodem, następuje natychmiastowe ponowne nawiązanie połączenia, a nie oczekiwanie na czas trwania następnego interwału ponownego połączenia. To zachowanie ma na celu wznowienie połączenia tak szybko, jak to możliwe dla użytkownika.
Domyślny czas ponownego nawiązywania połączenia używa obliczonej strategii wycofywania. Pierwsze kilka ponownych prób połączenia następuje w krótkim odstępie czasu, zanim zostaną wprowadzone obliczone opóźnienia między próbami. Domyślna logika przetwarzania interwału ponawiania prób to szczegóły implementacji, które mogą ulec zmianie bez powiadomienia, ale można znaleźć domyślną logikę Blazor używaną przez platformę w computeDefaultRetryInterval
funkcji (źródło 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).
Dostosuj zachowanie interwału ponawiania, określając funkcję, aby obliczyć interwał ponawiania prób. W poniższym przykładzie wycofywania wykładniczego liczba poprzednich prób ponownego połączenia jest pomnożona przez 1000 ms w celu obliczenia interwału ponawiania prób. Jeśli liczba poprzednich prób ponownego nawiązania połączenia (previousAttempts
) jest większa niż maksymalny limit ponawiania prób (maxRetries
), null
jest przypisywana do interwału ponawiania prób (retryIntervalMilliseconds
) w celu zaprzestania dalszych prób ponownego nawiązania połączenia:
Blazor.start({
circuit: {
reconnectionOptions: {
retryIntervalMilliseconds: (previousAttempts, maxRetries) =>
previousAttempts >= maxRetries ? null : previousAttempts * 1000
},
},
});
Alternatywą jest określenie dokładnej sekwencji interwałów ponawiania prób. Po ostatnim określonym interwale ponawiania próby ponowimy próbę zatrzymania, ponieważ retryIntervalMilliseconds
funkcja zwraca wartość undefined
:
Blazor.start({
circuit: {
reconnectionOptions: {
retryIntervalMilliseconds:
Array.prototype.at.bind([0, 1000, 2000, 5000, 10000, 15000, 30000]),
},
},
});
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. Interfejs użytkownika ponownego nawiązywania połączenia jest wyświetlany po osiągnięciu limitu czasu serwera na kliencie (withServerTimeout
sekcja Konfiguracja klienta). Jednak zmiana wartości parametru withServerTimeout
wymaga zmian w innych ustawieniach Keep-Alive, limitu czasu i uzgadniania opisanych w poniższych wskazówkach.
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 Web App (.NET 8 lub nowszy) w pliku projektu Program
serwera:
builder.Services.AddRazorComponents().AddInteractiveServerComponents()
.AddHubOptions(options =>
{
options.ClientTimeoutInterval = TimeSpan.FromSeconds(60);
options.HandshakeTimeout = TimeSpan.FromSeconds(30);
});
Blazor Server
Program
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 (Blazor) 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 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>
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 (Blazor) 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 SignalRobwód od klienta
Blazor
SignalR Obwód jest odłączony 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 Blazor zależności ASP.NET Core).
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 ASP.NET Podstawowe scenariusze zabezpieczeń i Blazor Web App dodatkowe scenariusze zabezpieczeń.
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.
Uruchamianie obwodu SignalR pod innym adresem URL
Zapobiegaj automatycznemu uruchamianiu aplikacji przez dodanie autostart="false"
do tagu Blazor<script>
(lokalizacji skryptu uruchamiania Blazor). Ręcznie ustanów adres URL obwodu przy użyciu Blazor.start
. W poniższych przykładach użyto ścieżki /signalr
.
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>
Dodaj następujące wywołanie MapBlazorHub ze ścieżką centrum do potoku przetwarzania oprogramowania pośredniczącego w pliku Program
aplikacji serwera.
Blazor Web Apps:
app.MapBlazorHub("/signalr");
Blazor Server:
Pozostaw istniejące wywołanie do MapBlazorHub w pliku i dodaj nowe wywołanie do MapBlazorHub ze ścieżką:
app.MapBlazorHub();
+ app.MapBlazorHub("/signalr");
IHttpContextAccessor
/HttpContext
IHttpContextAccessor zazwyczaj należy unikać z renderowaniem interaktywnym, ponieważ prawidłowe HttpContext nie zawsze dostępne.
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 ASP.NET Core po stronie serwera i Blazor Web App dodatkowe scenariusze zabezpieczeń.
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 ASP.NET Core po stronie serwera i Blazor Web App dodatkowe scenariusze zabezpieczeń.
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 ASP.NET Podstawowe scenariusze zabezpieczeń i Blazor Web App dodatkowe scenariusze zabezpieczeń.
Dodatkowe zasoby po stronie serwera
- Wskazówki dotyczące hosta i wdrażania po stronie serwera: SignalR konfiguracja
- Omówienie platformy ASP.NET Core SignalR
- Konfiguracja SignalR na platformie ASP.NET Core
- Dokumentacja zabezpieczeń po stronie serwera
- Uwierzytelnianie i autoryzacja w aplikacjach Blazor na platformie ASP.NET Core
- Uwierzytelnianie i autoryzacja w aplikacjach Blazor na platformie ASP.NET Core
- Wskazówki dotyczące ograniczania zagrożeń na potrzeby interaktywnego renderowania po stronie serwera ASP.NET Core Blazor
- ASP.NET Core po stronie serwera i Blazor Web App dodatkowe scenariusze zabezpieczeń
- Zdarzenia ponownego łączenia po stronie serwera i zdarzenia cyklu życia składnika
- Co to jest usługa platformy Azure SignalR ?
- Przewodnik dotyczący wydajności usługi platformy Azure SignalR
- Publikowanie aplikacji ASP.NET Core SignalR w usłudze aplikacja systemu Azure
-
dotnet/blazor-samples
(jak pobrać)