Sdílet prostřednictvím


Pokyny pro ASP.NET Core BlazorSignalR

Poznámka:

Toto není nejnovější verze tohoto článku. Aktuální vydání najdete v článku pro verzi .NET 9.

Varování

Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální vydání najdete v článku pro verzi .NET 9.

Důležité

Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.

Aktuální vydání najdete v článku pro verzi .NET 9.

Tento článek vysvětluje, jak nakonfigurovat a spravovat SignalR připojení v Blazor aplikacích.

Obecné pokyny k konfiguraci ASP.NET Core najdete v tématech v části Přehled ASP.NET Core oblasti dokumentace, zejména konfiguraci ASP.NET Core.

Aplikace na straně serveru používají ke komunikaci s prohlížečem ASP.NET Core SignalR . SignalRPodmínky hostování a škálování se vztahují na aplikace na straně serveru.

Blazor funguje nejlépe při použití protokolu WebSocket jako SignalR přenosu kvůli nižší latenci, spolehlivosti a zabezpečení. Dlouhé dotazování se používá SignalR , když webSockets není k dispozici nebo když je aplikace explicitně nakonfigurovaná tak, aby používala dlouhé dotazování.

Služba Azure SignalR se stavovým opětovným připojením

Služba Azure SignalR se sadou SDK verze 1.26.1 nebo novější podporuje SignalR stavové opětovné připojení (WithStatefulReconnect).

Komprese protokolu WebSocket pro komponenty interaktivního serveru

Ve výchozím nastavení jsou součásti interaktivního serveru:

  • Povolte kompresi připojení WebSocket. DisableWebSocketCompression (výchozí: false) řídí kompresi protokolu WebSocket.

  • Přijměte direktivu frame-ancestors Content Security Policy (CSP) nastavenou na 'self', což je výchozí nastavení a povoluje pouze vložení aplikace do <iframe> původu, ze kterého se aplikace obsluhuje, pokud je povolena komprese nebo je poskytnuta konfigurace kontextu WebSocket.

Výchozí frame-ancestors CSP je možné změnit nastavením hodnoty ContentSecurityFrameAncestorsPolicy na null, pokud chcete nakonfigurovat CSP centralizovaným způsobem nebo 'none' pro ještě přísnější zásady. Když je frame-ancestors CSP spravován centralizovaným způsobem, je nutné aplikovat zásadu při vykreslení prvního dokumentu. Nedoporučujeme zásady úplně odebírat, protože aplikace bude zranitelná vůči útokům. Další informace najdete v tématu Vynucení zásad zabezpečení obsahu pro ASP.NET Core Blazor a v průvodci MDN CSP.

Pomocí ConfigureWebSocketAcceptContext nakonfigurujte WebSocketAcceptContext pro připojení Protokolu WebSocket, která používají součásti serveru. Ve výchozím nastavení se použije zásada, která umožňuje kompresi a nastaví CSP pro předky rámce definované v ContentSecurityFrameAncestorsPolicy .

Příklady použití:

Zakažte kompresi nastavením DisableWebSocketCompression na true, což snižuje zranitelnost aplikace vůči útokům, ale může vést ke snížení výkonu.

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

Pokud je komprese povolená, nakonfigurujte přísnější frame-ancestors CSP s hodnotou 'none' (vyžaduje se jednoduché uvozovky), což umožňuje kompresi protokolu WebSocket, ale brání prohlížečům v vkládání aplikace do <iframe>:

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

Pokud je povolena komprese, odeberte frame-ancestors CSP nastavením ContentSecurityFrameAncestorsPolicy na null. Tento scénář se doporučuje jenom pro aplikace, které nastavují CSP centralizovaným způsobem:

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

Důležité

Prohlížeče používají směrnice CSP z více hlaviček CSP pomocí nejpřísnější hodnoty zásad direktivy. Vývojář proto nemůže přidat záměrně nebo omylem slabší frame-ancestors zásadu než 'self'.

Jednoduché uvozovky jsou vyžadovány pro řetězcovou hodnotu přenesenou k ContentSecurityFrameAncestorsPolicy:

Nepodporované hodnoty:none, self

Podporované hodnoty:'none', 'self'

Mezi další možnosti patří zadání jednoho nebo více zdrojů pro hostování a zdrojů pro schémata.

Podívejte se na pokyny k mitigaci hrozeb pro ASP.NET Core interaktivní rendering na straně serveru pro vliv na zabezpečení. Další informace najdete v tématu Vynucení zásad zabezpečení obsahu pro ASP.NET core Blazor a CSP: frame-ancestors (dokumentace MDN).

Zakázání komprese odpovědí pro Hot Reload

Při použití Hot Reload zakažte middleware pro kompresi odpovědí v Development prostředí. Bez ohledu na to, jestli se používá výchozí kód ze šablony projektu, vždy volejte UseResponseCompression nejprve v kanálu zpracování požadavků.

V souboru Program:

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

Vyjednávání mezi různými doménami na straně SignalR klienta pro autentizaci

Tato část vysvětluje, jak nakonfigurovat SignalRzákladního klienta pro odesílání přihlašovacích údajů, jako jsou soubory cookie nebo hlavičky ověřování HTTP.

Použijte SetBrowserRequestCredentials k nastavení Include při požadavcích mezi zdroji 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);
    }
}

Pokud bylo vytvořeno připojení rozbočovače, přiřaďte HttpMessageHandler k možnost HttpMessageHandlerFactory:

private HubConnectionBuilder? hubConnection;

...

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

Předchozí příklad nakonfiguruje URL připojení hubu na absolutní URI na /chathub. Identifikátor URI lze také nastavit pomocí řetězce, například https://signalr.example.comnebo prostřednictvím konfigurace. Navigation je injektovaný NavigationManager.

Další informace najdete v tématu konfigurace SignalR ASP.NET Core.

Vykreslování na straně klienta

Pokud je předrenderování nakonfigurováno, dojde k němu dříve, než je navázáno připojení klienta k serveru. Další informace naleznete v tématu Prerender ASP.NET Základní Razor komponenty.

Pokud je předrenderování nakonfigurováno, dojde k němu dříve, než je navázáno připojení klienta k serveru. Další informace najdete v následujících článcích:

Předem vytyčovaná velikost stavu a SignalR omezení velikosti zprávy

Velikost stavu při předběžném renderování může překročit limit velikosti zprávy okruhu BlazorSignalR, což vede k následujícímu výsledku:

  • Okruh SignalR se nepodaří inicializovat s chybou v klientovi: Circuit host not initialized.
  • Uživatelské rozhraní pro opětovné připojení v klientovi se zobrazí, když okruh selže. Obnovení není možné.

Pokud chcete tento problém vyřešit, použijte některý z následujících přístupů:

  • Snižte množství dat, která vkládáte do předzpracovaného stavu.
  • SignalR Zvětšete limit velikosti zprávy. UPOZORNĚNÍ: Zvýšení limitu může zvýšit riziko DoS útoků.

Další prostředky na straně klienta

Použití spřažení relací (perzistentní relace) pro hostování webové farmy na straně serveru

Pokud se používá více než jeden backendový server, musí aplikace implementovat spřažení relací, označované také jako sticky sessions. Vazba relace zajišťuje, že se připojení klienta znovu naváže ke stejnému serveru, pokud dojde k přerušení spojení. To je důležité, protože stav klienta je uchováván pouze v paměti serveru, který jako první navázal připojení klienta.

Následující chyba je vyvolána aplikací, která na webfarmě nepovolila vazbu relací.

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

Další informace o spřažení relace s hostováním služby Azure App Service viz Hostování a nasazení aplikací ASP.NET Core na straně Blazor serveru.

Služba Azure SignalR

Volitelná služba Azure funguje ve spojení s rozbočovačem aplikace pro škálování serverové aplikace na velký počet souběžných připojení. Globální dosah služby a vysoce výkonná datová centra navíc výrazně pomáhají snížit latenci kvůli zeměpisné poloze.

Služba se nevyžaduje pro Blazor aplikace hostované ve službě Aplikace Azure Service nebo Azure Container Apps, ale může být užitečná v jiných hostitelských prostředích:

  • Pro usnadnění škálování kapacity připojení.
  • Řízení globální distribuce

Další informace najdete v tématu Hostování a nasazování aplikací na straně Blazorserveru ASP.NET Core.

Možnosti zpracovatele okruhů na straně serveru

Nakonfigurujte okruh pomocí CircuitOptions. Zobrazit výchozí hodnoty ve zdroji odkazu.

Poznámka:

Odkazy na dokumentaci k referenčnímu zdroji .NET obvykle načítají výchozí větev úložiště, která představuje aktuální vývoj pro příští verzi .NET. Pokud chcete vybrat značku pro konkrétní verzi, použijte rozevírací seznam pro přepnutí větví nebo značek. Další informace najdete v tématu Jak vybrat značku verze zdrojového kódu ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Přečtěte si nebo nastavte možnosti v souboru Program pomocí delegáta možností na AddInteractiveServerComponents. Zástupný {OPTION} symbol představuje možnost a {VALUE} zástupný symbol je hodnota.

V souboru Program:

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

Přečtěte si nebo nastavte možnosti v souboru Program pomocí delegáta možností na AddServerSideBlazor. Zástupný {OPTION} symbol představuje možnost a {VALUE} zástupný symbol je hodnota.

V souboru Program:

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

Přečtěte si nebo nastavte možnosti v Startup.ConfigureServices pomocí delegáta k nastavení možností ve AddServerSideBlazor. Zástupný {OPTION} symbol představuje možnost a {VALUE} zástupný symbol je hodnota.

V Startup.ConfigureServices z Startup.cs:

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

Chcete-li konfigurovat HubConnectionContext, použijte HubConnectionContextOptions s AddHubOptions. Zobrazení výchozích hodnot pro možnosti kontextu připojení centra v referenčním zdroji Pro popisy možností v dokumentaci viz konfigurace ASP.NET Core. Zástupný {OPTION} symbol představuje možnost a {VALUE} zástupný symbol je hodnota.

Poznámka:

Odkazy na dokumentaci k referenčnímu zdroji .NET obvykle načítají výchozí větev úložiště, která představuje aktuální vývoj pro příští verzi .NET. Pokud chcete vybrat značku pro konkrétní verzi, použijte rozevírací seznam pro přepnutí větví nebo značek. Další informace najdete v tématu Jak vybrat značku verze zdrojového kódu ASP.NET Core (dotnet/AspNetCore.Docs #26205).

V souboru Program:

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

V souboru Program:

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

V Startup.ConfigureServices z Startup.cs:

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

Varování

Výchozí hodnota MaximumReceiveMessageSize je 32 kB. Zvýšení hodnoty může zvýšit riziko útoků DoS (Denial of Service).

Blazor spoléhá na MaximumParallelInvocationsPerClient hodnotu 1, což je výchozí hodnota. Další informace naleznete v tématu MaximumParallelInvocationsPerClient > 1 narušuje nahrávání souborů v Blazor Server režimu (dotnet/aspnetcore #53951).

Informace o správě paměti najdete v tématu Správa paměti v nasazených aplikacích na straně Blazor serveru ASP.NET Core.

Blazor Možnosti rozbočovače

Nakonfigurujte MapBlazorHub možnosti pro řízení HttpConnectionDispatcherOptionsBlazor hubu. Zobrazit výchozí nastavení pro volby spojení rozbočovače v referenčním zdroji . Zástupný {OPTION} symbol představuje možnost a {VALUE} zástupný symbol je hodnota.

Poznámka:

Odkazy na dokumentaci k referenčnímu zdroji .NET obvykle načítají výchozí větev úložiště, která představuje aktuální vývoj pro příští verzi .NET. Pokud chcete vybrat značku pro konkrétní verzi, použijte rozevírací seznam pro přepnutí větví nebo značek. Další informace najdete v tématu Jak vybrat značku verze zdrojového kódu ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Volání app.MapBlazorHub umístěte za volání app.MapRazorComponents do souboru aplikace Program:

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

Konfigurace hubu použitého AddInteractiveServerRenderMode s MapBlazorHub selže s chybou AmbiguousMatchException:

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

Pokud chcete tento problém vyřešit u aplikací, které cílí na .NET 8, dejte vlastnímu nakonfigurovanému hubu vyšší prioritu pomocí metody Blazor:

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

Další informace naleznete v následujících zdrojích:

Zadejte možnosti pro app.MapBlazorHub do souboru Program v aplikaci.

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

Uveďte možnosti ke app.MapBlazorHub v konfiguraci směrování koncového bodu:

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

Maximální velikost příjmu zprávy

Tato část se vztahuje pouze na projekty, které implementují SignalR.

Maximální povolená velikost příchozí SignalR zprávy pro metody rozbočovače je omezena podle nastavení HubOptions.MaximumReceiveMessageSize (výchozí hodnota: 32 kB). SignalR zprávy větší než MaximumReceiveMessageSize vyvolají chybu. Architektura neukládá omezení velikosti SignalR zprávy z centra na klienta.

Pokud SignalR není protokolování nastaveno na Ladění nebo Trasování, chyba velikosti zprávy se zobrazí pouze v konzoli nástrojů pro vývojáře v prohlížeči:

Chyba: Připojení bylo odpojeno s chybou Chyba: Server vrátil chybu při zavření: Připojení se ukončilo s chybou.

Pokud SignalR je protokolování na straně serveru nastaveno na ladění nebo trasování, protokolování na straně serveru zobrazí InvalidDataException chybu velikosti zprávy.

appsettings.Development.json:

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

Chyba:

System.IO.InvalidDataException: Byla překročena maximální velikost zprávy 32768B. Velikost zprávy se dá nakonfigurovat v AddHubOptions.

Jedním z přístupů je zvýšení limitu nastavením MaximumReceiveMessageSize v Program souboru. Následující příklad nastaví maximální velikost příjmu zprávy na 64 kB:

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

Zvýšení limitu SignalR velikosti příchozích zpráv s sebou nese nároky na více prostředků serveru a zvyšuje riziko útoků Denial of Service (DoS). Navíc čtení velkého množství obsahu do paměti jako řetězců nebo bajtových polí může také vést k přidělení, která neefektivně spolupracují s garbage collectorem, což má za následek dodatečné výkonnostní postihy.

Lepší možností pro čtení velkých datových částí je odeslat obsah v menších blocích a zpracovat datovou část jako .Stream To lze použít při čtení velkých JSON zatížení z JavaScript JS interopu nebo pokud je JS interop data dostupná jako nezpracované bajty. Pro příklad, který ukazuje odesílání velkých binárních datových částí v serverových aplikacích používajících techniky podobné InputFile komponentě, se podívejte na ukázkovou aplikaci Binary Submit a BlazorInputLargeTextArea vzorovou aplikaci komponent.

Poznámka:

Odkazy na dokumentaci k referenčnímu zdroji .NET obvykle načítají výchozí větev úložiště, která představuje aktuální vývoj pro příští verzi .NET. Pokud chcete vybrat značku pro konkrétní verzi, použijte rozevírací seznam pro přepnutí větví nebo značek. Další informace najdete v tématu Jak vybrat značku verze zdrojového kódu ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Formuláře, které zpracovávají velké datové balíčky, můžou také přímo používat streamovací rozhraní SignalRJS. Další informace naleznete v tématu Volání metod .NET z funkcí JavaScriptu v ASP.NET Core Blazor. Příklad formulářů, který streamuje <textarea> data na server, najdete v článku Řešení potíží s Blazor formuláři v ASP.NET Core.

Jedním z přístupů je zvýšení limitu nastavením MaximumReceiveMessageSize v Program souboru. Následující příklad nastaví maximální velikost příjmu zprávy na 64 kB:

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

Zvýšení limitu SignalR velikosti příchozích zpráv s sebou nese nároky na více prostředků serveru a zvyšuje riziko útoků Denial of Service (DoS). Navíc čtení velkého množství obsahu do paměti jako řetězců nebo bajtových polí může také vést k přidělení, která neefektivně spolupracují s garbage collectorem, což má za následek dodatečné výkonnostní postihy.

Lepší možností pro čtení velkých datových částí je odeslat obsah v menších blocích a zpracovat datovou část jako .Stream To lze použít při čtení velkých JSON zatížení z JavaScript JS interopu nebo pokud je JS interop data dostupná jako nezpracované bajty. Příklad, který ukazuje odesílání velkých binárních datových částí v Blazor Server pomocí technik podobných komponentě InputFile, naleznete v ukázkové aplikaci Binary Submit a v ukázce komponenty BlazorInputLargeTextArea.

Poznámka:

Odkazy na dokumentaci k referenčnímu zdroji .NET obvykle načítají výchozí větev úložiště, která představuje aktuální vývoj pro příští verzi .NET. Pokud chcete vybrat značku pro konkrétní verzi, použijte rozevírací seznam pro přepnutí větví nebo značek. Další informace najdete v tématu Jak vybrat značku verze zdrojového kódu ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Formuláře, které zpracovávají velké datové balíčky, můžou také přímo používat streamovací rozhraní SignalRJS. Další informace naleznete v tématu Volání metod .NET z funkcí JavaScriptu v ASP.NET Core Blazor. Pro příklad formulářů, který streamuje <textarea> data v aplikaci Blazor Server, se podívejte na Řešení problémů ASP.NET Core Blazor formulářů.

Zvýšení limitu nastavením MaximumReceiveMessageSize v Startup.ConfigureServices:

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

Zvýšení limitu SignalR velikosti příchozích zpráv s sebou nese nároky na více prostředků serveru a zvyšuje riziko útoků Denial of Service (DoS). Navíc čtení velkého množství obsahu do paměti jako řetězců nebo bajtových polí může také vést k přidělení, která neefektivně spolupracují s garbage collectorem, což má za následek dodatečné výkonnostní postihy.

Při vývoji kódu, který přenáší velké množství dat, zvažte následující pokyny:

  • Využijte nativní podporu streamovací interoperability JS pro přenos dat, která překračují SignalR limit velikosti příchozí zprávy.
  • Obecné tipy:
    • Nealokujte velké objekty v JS a v kódu C#.
    • Volné spotřebované paměti po dokončení nebo zrušení procesu
    • Vynucujte následující další požadavky pro účely zabezpečení:
      • Deklarujte maximální velikost souboru nebo dat, které lze předat.
      • Deklarujte minimální rychlost nahrávání z klienta na server.
    • Po přijetí dat serverem mohou být tato data následující:
      • Dočasně uložené ve vyrovnávací paměti, dokud nejsou všechny segmenty shromážděny.
      • Spotřebováno okamžitě. Data se například dají okamžitě uložit do databáze nebo zapisovat na disk při přijetí jednotlivých segmentů.
  • Rozdělte data na menší části a posílejte datové segmenty postupně, dokud server neobdrží všechna data.
  • Nealokujte velké objekty v JS a v kódu C#.
  • Při odesílání nebo přijímání dat neblokujte hlavní vlákno uživatelského rozhraní po dlouhou dobu.
  • Volné spotřebované paměti po dokončení nebo zrušení procesu
  • Vynucujte následující další požadavky pro účely zabezpečení:
    • Deklarujte maximální velikost souboru nebo dat, které lze předat.
    • Deklarujte minimální rychlost nahrávání z klienta na server.
  • Po přijetí dat serverem mohou být tato data následující:
    • Dočasně uložené ve vyrovnávací paměti, dokud nejsou všechny segmenty shromážděny.
    • Spotřebováno okamžitě. Data se například dají okamžitě uložit do databáze nebo zapisovat na disk při přijetí jednotlivých segmentů.

Blazor Konfigurace směrování koncového bodu Hubu na serverové straně

V souboru Program zavolejte MapBlazorHub pro namapování BlazorHub na výchozí cestu aplikace. Skript Blazor (blazor.*.js) automaticky odkazuje na koncový bod vytvořený MapBlazorHub.

Reflektujte stav připojení na straně serveru v uživatelském rozhraní.

Pokud klient zjistí ztracené připojení k serveru, zobrazí se uživateli výchozí uživatelské rozhraní, zatímco se klient pokusí znovu připojit:

Výchozí uživatelské rozhraní pro opětovné připojení.

Výchozí uživatelské rozhraní pro opětovné připojení.

Pokud se opětovné připojení nezdaří, uživateli se zobrazí pokyn, aby se znovu zkusil nebo znovu načte stránku:

Výchozí uživatelské rozhraní pro opakování pokusu.

Výchozí uživatelské rozhraní pro opakování pokusu.

Pokud opětovné připojení proběhne úspěšně, stav uživatele se často ztratí. Vlastní kód lze přidat do libovolné komponenty, aby se při selhání připojení uložil a znovu načítá stav uživatele. Další informace najdete v tématu ASP.NET Core Blazor správa stavu.

Pokud chcete vytvořit prvky uživatelského rozhraní, které sledují stav opětovného připojení, popisuje následující tabulka:

  • Sada tříd CSS components-reconnect-* (třída CSS sloupec), které jsou nastaveny nebo vypnuty pomocí Blazor na prvku s vlastností idcomponents-reconnect-modal.
  • Událost components-reconnect-state-changed (sloupecUdálost), která označuje změnu stavu opětovného připojení.
CSS třída Událost Označuje...
components-reconnect-show show Ztracené připojení. Klient se pokouší znovu připojit. Zobrazí se dialog opětovného připojení.
components-reconnect-hide hide Na serveru se znovu naváže aktivní připojení. Model opětovného připojení je zavřený.
components-reconnect-retrying retrying Klient se pokouší znovu připojit.
components-reconnect-failed failed Opětovné připojení se nezdařilo, pravděpodobně kvůli selhání sítě.
components-reconnect-rejected rejected Opětovné připojení bylo odmítnuto.

Když se stav opětovného připojení v components-reconnect-state-changed změní na failed, zavolejte v JavaScriptu Blazor.reconnect() a pokuste se o opětovné připojení.

Když dojde ke změně stavu opětovného připojení na rejected, bylo navázáno spojení se serverem, ale ten odmítl připojení, a uživatelský stav na serveru je ztracen. Pokud chcete aplikaci znovu načíst, zavolejte location.reload() v JavaScriptu. Tento stav připojení může mít za následek následující:

  • V okruhu na straně serveru dojde k selhání.
  • Klient je odpojen natolik dlouho, že server resetuje stav uživatele. Instance komponent uživatele jsou likvidovány.
  • Server se restartuje nebo se pracovní proces aplikace recykluje.

Vývojář přidá posluchač událostí k prvku modálního okna pro opětovné připojení, aby monitoroval a reagoval na změny stavu opětovného připojení, jak je vidět v následujícím příkladu.

const reconnectModal = document.getElementById("components-reconnect-modal");
reconnectModal.addEventListener("components-reconnect-state-changed", 
  handleReconnectStateChanged);

function handleReconnectStateChanged(event) {
  if (event.detail.state === "show") {
    reconnectModal.showModal();
  } else if (event.detail.state === "hide") {
    reconnectModal.close();
  } else if (event.detail.state === "failed") {
    Blazor.reconnect();
  } else if (event.detail.state === "rejected") {
    location.reload();
  }
}

Prvek s označením id a components-reconnect-max-retries zobrazuje maximální počet pokusů o opětovné připojení:

<span id="components-reconnect-max-retries"></span>

Prvek s id a components-reconnect-current-attempt zobrazuje aktuální pokus o opětovné připojení:

<span id="components-reconnect-current-attempt"></span>

Prvek s id o hodnotě components-seconds-to-next-attempt zobrazuje počet sekund do dalšího pokusu o opětovné připojení:

<span id="components-seconds-to-next-attempt"></span>

Šablona projektu Blazor Web App obsahuje komponentu ReconnectModal (Components/Layout/ReconnectModal.razor) s kompletovanými soubory stylů a javascriptovými soubory (ReconnectModal.razor.css, ReconnectModal.razor.js), které je možné přizpůsobit podle potřeby. Tyto soubory je možné prozkoumat v referenčním zdroji ASP.NET Core nebo kontrolou aplikace vytvořené ze šablony projektu Blazor Web App. Komponenta se přidá do projektu, když je projekt vytvořen v sadě Visual Studio s interaktivním režimem vykreslování nastaveným na Server nebo Auto, nebo je vytvořen pomocí nástroje .NET CLI s volbou --interactivity server (výchozí) nebo --interactivity auto.

Poznámka:

Odkazy na dokumentaci k referenčnímu zdroji .NET obvykle načítají výchozí větev úložiště, která představuje aktuální vývoj pro příští verzi .NET. Pokud chcete vybrat značku pro konkrétní verzi, použijte rozevírací seznam pro přepnutí větví nebo značek. Další informace najdete v tématu Jak vybrat značku verze zdrojového kódu ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Chcete-li přizpůsobit uživatelské rozhraní, definujte jeden prvek s id a components-reconnect-modal v obsahu elementu <body>. Následující příklad umístí prvek do App komponenty.

App.razor:

Chcete-li přizpůsobit uživatelské rozhraní, definujte jeden prvek s id a components-reconnect-modal v obsahu elementu <body>. Následující příklad umístí prvek na stránku hostitele.

Pages/_Host.cshtml:

Chcete-li přizpůsobit uživatelské rozhraní, definujte jeden prvek s id a components-reconnect-modal v obsahu elementu <body>. Následující příklad umístí prvek na stránku rozložení.

Pages/_Layout.cshtml:

Chcete-li přizpůsobit uživatelské rozhraní, definujte jeden prvek s id a components-reconnect-modal v obsahu elementu <body>. Následující příklad umístí prvek na stránku hostitele.

Pages/_Host.cshtml:

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

Poznámka:

Pokud aplikace vykresluje více než jeden prvek s id typu components-reconnect-modal, pouze první vykreslený prvek obdrží změny třídy CSS ke zobrazení nebo skrytí tohoto elementu.

Do šablony stylů webu přidejte následující styly CSS.

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

Následující tabulka popisuje třídy CSS použité u components-reconnect-modal elementu rozhraním Blazor .

CSS třída Označuje...
components-reconnect-show Ztracené připojení. Klient se pokouší znovu připojit. Zobrazit dialogové okno.
components-reconnect-hide Na serveru se znovu naváže aktivní připojení. Skryjte dialogové okno.
components-reconnect-failed Opětovné připojení se nezdařilo, pravděpodobně kvůli selhání sítě. Pokud se chcete pokusit znovu připojit, zavolejte window.Blazor.reconnect() v JavaScriptu.
components-reconnect-rejected Opětovné připojení bylo odmítnuto. Server byl dosažen, ale odmítl připojení a stav uživatele na serveru se ztratil. Pokud chcete aplikaci znovu načíst, zavolejte location.reload() v JavaScriptu. Tento stav připojení může mít za následek následující:
  • V okruhu na straně serveru dojde k selhání.
  • Klient je odpojen natolik dlouho, že server resetuje stav uživatele. Instance komponent uživatele jsou likvidovány.
  • Server se restartuje nebo se pracovní proces aplikace recykluje.

Přizpůsobte zpoždění před zobrazením uživatelského rozhraní pro opětovné připojení nastavením transition-delay vlastnosti v šabloně stylů CSS webu pro modální prvek. Následující příklad nastaví zpoždění přechodu z 500 ms (výchozí) na 1 000 ms (1 sekunda).

wwwroot/app.css:

wwwroot/css/site.css:

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

Chcete-li zobrazit aktuální pokus o opětovné připojení, definujte prvek s `id` a `components-reconnect-current-attempt`. Chcete-li zobrazit maximální počet opakovaných pokusů o opětovné připojení, definujte prvek s id nastaveným na components-reconnect-max-retries. Následující příklad umístí tyto prvky do modálního prvku pokusu o opětovné připojení za předchozím příkladem.

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

Když se zobrazí modální okno vlastního opětovného připojení, zobrazí následující obsah s počítadlem pokusů o opětovné připojení.

Došlo k problému s připojením! (Aktuální pokus o opětovné připojení: 1 / 8)

Vykreslování na straně serveru

Ve výchozím nastavení jsou komponenty předváděné na serveru před navázáním připojení klienta k serveru. Další informace naleznete v tématu Prerender ASP.NET Základní Razor komponenty.

Ve výchozím nastavení jsou komponenty předváděné na serveru před navázáním připojení klienta k serveru. Další informace naleznete v sekci Pomocník značky komponenty v ASP.NET Core.

Monitorování aktivity obvodu na straně serveru

Sledujte příchozí aktivitu okruhu pomocí metody CreateInboundActivityHandler na CircuitHandler. Příchozí aktivita okruhu je jakákoli aktivita odesílaná z prohlížeče na server, například události UI nebo volání interoperability z JavaScriptu do .NET.

Například můžete použít obslužnou rutinu aktivity okruhu k zjištění, zda je klient nečinný, a k zaznamenání jeho ID okruhu (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;
    }
}

Zaregistrujte službu v Program souboru. Následující příklad nakonfiguruje výchozí časový limit nečinnosti pět minut až pět sekund, aby bylo možné otestovat předchozí IdleCircuitHandler implementaci:

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

Obslužné rutiny aktivit obvodu také poskytují přístup k definovaným Blazor službám z jiných Blazor rozsahů injektáže závislostí (DI). Další informace a příklady najdete tady:

Blazor spuštění

Nakonfigurujte ruční spuštění okruhu BlazorSignalR v App.razor souboru Blazor Web App:

Nakonfigurujte ruční spuštění okruhu BlazorSignalR v souboru Pages/_Host.cshtml (Blazor Server):

Nakonfigurujte ruční spuštění okruhu BlazorSignalR v souboru Pages/_Layout.cshtml (Blazor Server):

Nakonfigurujte ruční spuštění okruhu BlazorSignalR v souboru Pages/_Host.cshtml (Blazor Server):

  • Přidejte atribut autostart="false" do značky <script> pro skript blazor.*.js.
  • Umístěte skript, který volá Blazor.start(), poté, co je načten skript Blazor, a to uvnitř koncové značky </body>.

Když je autostart zakázána, funguje normálně každý aspekt aplikace, který není závislý na obvodu. Například směrování na straně klienta je funkční. Jakýkoli aspekt, který závisí na okruhu, není funkční, dokud se nezavolá Blazor.start(). Chování aplikace je nepředvídatelné bez zavedeného okruhu. Například metody komponent se nespustí při odpojení okruhu.

Další informace, včetně toho, jak inicializovat Blazor, když je dokument připravený a jak se zřetězit s JS Promise, viz ASP.NET Core Blazor startup.

Konfigurace SignalR časových limitů a Keep-Alive u klienta

Nakonfigurujte pro klienta následující hodnoty:

  • withServerTimeout: Nakonfiguruje časový limit serveru v milisekundách. Pokud tento časový limit uplynou bez příjmu zpráv ze serveru, připojení se ukončí s chybou. Výchozí hodnota časového limitu je 30 sekund. Časový limit serveru by měl být alespoň dvojnásobný, než je hodnota přiřazená intervalu keep-Alive (withKeepAliveInterval).
  • withKeepAliveInterval: Nakonfiguruje interval Keep-Alive v milisekundách (výchozí interval, ve kterém se má server otestovat příkazem ping). Toto nastavení umožňuje serveru rozpoznat pevné odpojení, například když klient odpojí počítač od sítě. Příkaz ping se vyskytuje nanejvýš tak často, jak server provádí ping. Pokud server odešle příkaz ping každých pět sekund, přiřazení hodnoty nižší než 5000 (5 sekund) způsobí, že server stále odesílá příkaz ping každých pět sekund. Výchozí hodnota je 15 sekund. Interval Keep-Alive by měl být menší nebo roven polovině hodnoty přiřazené k vypršení časového limitu serveru (withServerTimeout).

Následující příklad souboru App.razor (Blazor Web App) ukazuje přiřazení výchozích hodnot.

Blazor Web App:

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

Následující příklad souboru Pages/_Host.cshtml (Blazor Servervšechny verze kromě ASP.NET Core v .NET 6) nebo Pages/_Layout.cshtml soubor (Blazor ServerASP.NET Core v .NET 6).

Blazor Server:

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

V předchozím příkladu je zástupný symbol {BLAZOR SCRIPT} cestou ke skriptu a název souboru je Blazor. Umístění skriptu a cestu, kterou je třeba použít, naleznete v části struktura projektu ASP.NET Core Blazor.

Při vytváření připojení rozbočovače v komponentě nastavte ServerTimeout (výchozí: 30 sekund) a KeepAliveInterval (výchozí: 15 sekund) na HubConnectionBuilder. Nastavte HandshakeTimeout (výchozí: 15 sekund) na sestavené HubConnection. Následující příklad ukazuje přiřazení výchozích hodnot:

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

Nakonfigurujte pro klienta následující hodnoty:

  • serverTimeoutInMilliseconds: Časový limit serveru v milisekundách. Pokud tento časový limit uplynou bez příjmu zpráv ze serveru, připojení se ukončí s chybou. Výchozí hodnota časového limitu je 30 sekund. Časový limit serveru by měl být alespoň dvojnásobný, než je hodnota přiřazená intervalu keep-Alive (keepAliveIntervalInMilliseconds).
  • keepAliveIntervalInMilliseconds: Výchozí interval, ve kterém se má server otestovat příkazem ping. Toto nastavení umožňuje serveru rozpoznat pevné odpojení, například když klient odpojí počítač od sítě. Příkaz ping se vyskytuje nanejvýš tak často, jak server provádí ping. Pokud server odešle příkaz ping každých pět sekund, přiřazení hodnoty nižší než 5000 (5 sekund) způsobí, že server stále odesílá příkaz ping každých pět sekund. Výchozí hodnota je 15 sekund. Interval Keep-Alive by měl být menší nebo roven polovině hodnoty přiřazené k vypršení časového limitu serveru (serverTimeoutInMilliseconds).

Následující příklad souboru Pages/_Host.cshtml (Blazor Servervšechny verze kromě ASP.NET Core v .NET 6) nebo Pages/_Layout.cshtml soubor (Blazor ServerASP.NET Core v .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>

V předchozím příkladu je zástupný symbol {BLAZOR SCRIPT} cestou ke skriptu a název souboru je Blazor. Umístění skriptu a cestu, kterou je třeba použít, naleznete v části struktura projektu ASP.NET Core Blazor.

Při vytváření připojení k rozbočovači v komponentě nastavte ServerTimeout (výchozí: 30 sekund), HandshakeTimeout (výchozí: 15 sekund) a KeepAliveInterval (výchozí: 15 sekund) pro sestavený HubConnection. Následující příklad ukazuje přiřazení výchozích hodnot:

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

Při změně hodnot časového limitu serveru (ServerTimeout) nebo intervalu Keep-Alive (KeepAliveInterval):

  • Časový limit serveru by měl být alespoň dvojnásobný, než je hodnota přiřazená intervalu Keep-Alive.
  • Interval Keep-Alive by měl být menší nebo roven polovině hodnoty přiřazené k vypršení časového limitu serveru.

Další informace najdete v částech globálního nasazení a selhání připojení v následujících článcích:

Úprava obslužné rutiny opětovného připojení na straně serveru

Události spojení okruhu obslužné rutiny pro opětovné připojení je možné upravit pro vlastní chování, například:

  • Chcete-li upozornit uživatele, pokud je připojení ukončeno.
  • Pro provedení logování z klienta při připojení okruhu.

Pokud chcete upravit události připojení, zaregistrujte zpětná volání pro následující změny připojení:

  • Zrušená připojení používají onConnectionDown.
  • Navázaná/znovu navázaná připojení se používají onConnectionUp.

Je nutné zadat jak onConnectionDown, tak 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>

V předchozím příkladu je zástupný symbol {BLAZOR SCRIPT} cestou ke skriptu a název souboru je Blazor. Umístění skriptu a cestu, kterou je třeba použít, naleznete v části struktura projektu ASP.NET Core Blazor.

Automatická aktualizace stránky při selhání opětovného připojení na straně serveru

Výchozí chování opětovného připojení vyžaduje, aby uživatel po selhání opětovného připojení ručně aktualizoval stránku. Nicméně, k automatickému obnovení stránky lze použít vlastní obslužná rutina opětovného připojení.

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>

V předchozím příkladu je zástupný symbol {BLAZOR SCRIPT} cestou ke skriptu a název souboru je Blazor. Umístění skriptu a cestu, kterou je třeba použít, naleznete v části struktura projektu ASP.NET Core Blazor.

Vytvořte následující wwwroot/boot.js soubor.

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

Další informace o spuštění Blazor viz spuštění ASP.NET Core Blazor.

Upravit počet pokusů o opětovné připojení a interval na straně serveru

Pokud chcete upravit počet opakování a interval opětovného připojení, nastavte počet opakování (maxRetries) a období v milisekundách povolených pro každý pokus o opakování (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>

V předchozím příkladu je zástupný symbol {BLAZOR SCRIPT} cestou ke skriptu a název souboru je Blazor. Umístění skriptu a cestu, kterou je třeba použít, naleznete v části struktura projektu ASP.NET Core Blazor.

Když se uživatel vrátí do aplikace s odpojeným okruhem, pokusí se o opětovné připojení okamžitě, a nečeká na dobu trvání dalšího intervalu opětovného připojení. Toto chování se snaží obnovit připojení co nejrychleji pro uživatele.

Výchozí časování opětovného připojení používá vypočítanou strategii zpětného odpojení. Několik opakovaných pokusů o opětovné připojení probíhá v rychlém sledu, než jsou zavedeny vypočítaná zpoždění mezi pokusy. Výchozí logika pro výpočet intervalu opakování je implementační detail, který se může bez předchozího upozornění změnit, nicméně můžete najít standardní logiku, kterou Blazor framework používá ve funkci computeDefaultRetryInterval (referenční zdroj).

Poznámka:

Odkazy na dokumentaci k referenčnímu zdroji .NET obvykle načítají výchozí větev úložiště, která představuje aktuální vývoj pro příští verzi .NET. Pokud chcete vybrat značku pro konkrétní verzi, použijte rozevírací seznam pro přepnutí větví nebo značek. Další informace najdete v tématu Jak vybrat značku verze zdrojového kódu ASP.NET Core (dotnet/AspNetCore.Docs #26205).

Přizpůsobte chování intervalu opakování zadáním funkce pro výpočet intervalu opakování. V následujícím příkladu exponenciálního backoffu je počet předchozích pokusů o opětovné připojení vynásoben 1 000 ms pro výpočet intervalu znovupokusů. Pokud je počet předchozích pokusů o opětovné připojení (previousAttempts) větší než maximální limit opakování (maxRetries), null je přiřazen k intervalu opakování (retryIntervalMilliseconds), aby se zastavily další pokusy o opětovné připojení:

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

Alternativou je určit přesnou sekvenci intervalů opakování. Po posledním zadaném intervalu opakování se opakování zastaví, protože retryIntervalMilliseconds funkce vrátí undefined:

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

Další informace o spuštění Blazor viz spuštění ASP.NET Core Blazor.

Ovládejte, kdy se zobrazí uživatelské rozhraní pro opětovné připojení

Řízení, kdy se zobrazí uživatelské rozhraní pro opětovné připojení, může být užitečné v následujících situacích:

  • Nasazená aplikace často zobrazuje rozhraní opětovného připojení kvůli vypršení časového limitu příkazu ping způsobeného zpožděním interní sítě nebo internetu, a proto byste chtěli zvýšit zpoždění.
  • Aplikace by měla nahlásit uživatelům, že připojení se dříve ukončilo, a chcete zkrátit zpoždění.

Načasování vzhledu uživatelského rozhraní pro opětovné připojení je ovlivněno úpravou intervalu zachování spojení a časových limitů na straně klienta. Uživatelské rozhraní pro opětovné připojení se zobrazí po dosažení časového limitu serveru v klientovi (withServerTimeoutoddíl Konfigurace klienta). Změna hodnoty withServerTimeout vyžaduje změny v jiných nastaveních Keep-Alive, timeout a handshake, jak je uvedeno v následujících pokynech.

Jako obecná doporučení pro následující pokyny:

  • Keep-Alive interval by se měl shodovat mezi konfigurací klienta a serveru.
  • Časové limity by měly být alespoň dvojnásobné, než je hodnota přiřazená intervalu Keep-Alive.

Konfigurace serveru

Nastavte následující:

  • ClientTimeoutInterval (výchozí hodnota: 30 sekund): Klienti časového intervalu musí odeslat zprávu předtím, než server připojení zavře.
  • HandshakeTimeout (výchozí hodnota: 15 sekund): Interval, který server používá k časovému omezení příchozích požadavků na handshake od klientů.
  • KeepAliveInterval (výchozí hodnota: 15 sekund): Interval používaný serverem k vysílání udržovacích pingů připojeným klientům. Všimněte si, že v klientovi je také nastavení intervalu Keep-Alive, které by mělo odpovídat hodnotě serveru.

ClientTimeoutInterval a HandshakeTimeout mohou být zvýšeny, a KeepAliveInterval může zůstat stejný. Důležité je, že pokud změníte hodnoty, ujistěte se, že časové limity jsou alespoň dvojnásobné hodnoty intervalu Keep-Alive a že interval Keep-Alive odpovídá mezi serverem a klientem. Další informace najdete v části Konfigurace SignalR časových limitů a Keep-Alive na klientu.

V následujícím příkladu:

  • Hodnota ClientTimeoutInterval se zvýší na 60 sekund (výchozí hodnota: 30 sekund).
  • Hodnota HandshakeTimeout se zvýší na 30 sekund (výchozí hodnota: 15 sekund).
  • Není KeepAliveInterval nastaven v kódu vývojáře a používá výchozí hodnotu 15 sekund. Snížení hodnoty intervalu Keep-Alive zvyšuje frekvenci příkazů ping pro komunikaci, což zvyšuje zatížení aplikace, serveru a sítě. Je třeba dbát na to, abyste se vyhnuli špatnému výkonu při snížení intervalu Keep-Alive.

Blazor Web App (.NET 8 nebo novější) v souboru serverového projektu Program:

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

Blazor Server v Program souboru:

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

Další informace najdete v části Možnosti obslužné rutiny okruhu na straně serveru.

Konfigurace klienta

Nastavte následující:

  • withServerTimeout (výchozí hodnota: 30 sekund): Nakonfiguruje časový limit serveru zadaný v milisekundách pro připojení rozbočovače okruhu.
  • withKeepAliveInterval (výchozí hodnota: 15 sekund): Interval zadaný v milisekundách, ve kterém připojení odesílá zprávy Keep-Alive.

Časový limit serveru je možné zvýšit a interval Keep-Alive může zůstat stejný. Důležité je, že pokud změníte hodnoty, ujistěte se, že časový limit serveru je alespoň dvojnásobná hodnota intervalu Keep-Alive a že hodnoty intervalu Keep-Alive odpovídají mezi serverem a klientem. Další informace najdete v části Konfigurace SignalR časových limitů a Keep-Alive na klientu.

V následujícím příkladu konfigurace spuštění (umístění Blazor skriptu) se pro vypršení časového limitu serveru použije vlastní hodnota 60 sekund. Interval Keep-Alive (withKeepAliveInterval) není nastavený a používá výchozí hodnotu 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>

Při vytváření připojení rozbočovače v komponentě nastavte časový limit serveru (WithServerTimeout, výchozí hodnota: 30 sekund) na HubConnectionBuilder. Nastavte HandshakeTimeout (výchozí: 15 sekund) na sestavené HubConnection. Ověřte, že časové limity jsou alespoň dvojnásobkem intervalu Keep-Alive (WithKeepAliveInterval/KeepAliveInterval) a že hodnota Keep-Alive je shodná mezi serverem a klientem.

Následující příklad je založen na komponentě Index v kurzu SignalR s Blazor. Časový limit serveru se zvýší na 60 sekund a časový limit handshake se zvýší na 30 sekund. Interval Keep-Alive není nastavený a používá výchozí hodnotu 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();
}

Nastavte následující:

  • serverTimeoutInMilliseconds (výchozí hodnota: 30 sekund): Nakonfiguruje časový limit serveru zadaný v milisekundách pro připojení rozbočovače okruhu.
  • keepAliveIntervalInMilliseconds (výchozí hodnota: 15 sekund): Interval zadaný v milisekundách, ve kterém připojení odesílá zprávy Keep-Alive.

Časový limit serveru je možné zvýšit a interval Keep-Alive může zůstat stejný. Důležité je, že pokud změníte hodnoty, ujistěte se, že časový limit serveru je alespoň dvojnásobná hodnota intervalu Keep-Alive a že hodnoty intervalu Keep-Alive odpovídají mezi serverem a klientem. Další informace najdete v části Konfigurace SignalR časových limitů a Keep-Alive na klientu.

V následujícím příkladu konfigurace spuštění (umístění Blazor skriptu) se pro vypršení časového limitu serveru použije vlastní hodnota 60 sekund. Interval Keep-Alive (keepAliveIntervalInMilliseconds) není nastavený a používá výchozí hodnotu 15 sekund.

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

Při vytváření připojení rozbočovače v komponentě nastavte ServerTimeout (výchozí: 30 sekund) a HandshakeTimeout (výchozí: 15 sekund) na vytvořeném HubConnection. Ověřte, že časové limity jsou nejméně dvojnásobkem intervalu Keep-Alive. Ověřte, že interval udržování spojení odpovídá mezi serverem a klientem.

Následující příklad je založen na komponentě Index v kurzu SignalR s Blazor. Zvýší se ServerTimeout na 60 sekund a HandshakeTimeout zvýší se na 30 sekund. Interval Keep-Alive (KeepAliveInterval) není nastavený a používá výchozí hodnotu 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();
}

Odpojte Blazorokruh SignalR od klienta

Blazor SignalR Okruh se odpojí při unload aktivaci události stránky. Chcete-li odpojit obvod pro jiné scénáře, vyvolejte Blazor.disconnect v příslušné obslužné rutině události. V následujícím příkladu se okruh odpojí, když je stránka skrytá (pagehide událost):

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

Další informace o spuštění Blazor viz spuštění ASP.NET Core Blazor.

Obsluha okruhu na straně serveru

Můžete definovat obslužnou rutinu okruhu, která umožňuje spouštění kódu při změnách stavu uživatelského okruhu. Obslužná rutina okruhu je implementována tím, že se odvodí z CircuitHandler a zaregistruje se třída v kontejneru služeb aplikace. Následující příklad obsluhy obvodu sleduje otevřená SignalR připojení.

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

Obsluhy okruhu se registrují pomocí DI. Instance s vymezeným oborem se vytvářejí pro každou instanci okruhu. Pomocí TrackingCircuitHandler v předchozím příkladu se vytvoří singletonová služba, protože musí být sledován stav všech okruhů.

V souboru Program:

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

V Startup.ConfigureServices z Startup.cs:

services.AddSingleton<CircuitHandler, TrackingCircuitHandler>();

Pokud metody správce vlastního okruhu vyvolají neošetřenou výjimku, je tato výjimka pro okruh smrtelná. Chcete-li tolerovat výjimky v kódu obslužné rutiny nebo volaných metodách, zabalte kód do jednoho nebo více try-catch příkazů pomocí zpracování chyb a protokolování.

Když okruh skončí, protože se uživatel odpojil a rámec čistí stav okruhu, rámec zruší rozsah DI okruhu. Zničení rozsahu zničí všechny služby DI v rámci obvodu, které implementují System.IDisposable. Pokud některá služba DI během vyřazení vyvolá neošetřenou výjimku, architektura ji zaznamená do protokolu. Další informace najdete v tématu ASP.NET Core Blazor injektáž závislostí.

Zpracovatel okruhu na straně serveru pro sledování uživatelů pro přizpůsobené služby

Použijte CircuitHandler k zachycení uživatele z AuthenticationStateProvider a nastavte tohoto uživatele ve službě. Další informace a ukázkový kód najdete v tématu ASP.NET Core na straně serveru a Blazor Web App v dalších scénářích zabezpečení.

Uzavření okruhů, pokud neexistují žádné zbývající součásti interaktivního serveru

Komponenty interaktivního serveru zpracovávají události webového uživatelského rozhraní pomocí připojení v reálném čase s prohlížečem označovaným jako okruh. Okruh a jeho přidružený stav se vytvoří, když se vykreslí kořenová součást Interactive Serveru. Okruh se zavře, pokud na stránce nejsou žádné zbývající součásti interaktivního serveru, které uvolní prostředky serveru.

Spusťte SignalR okruh na jiné adrese URL

Zabraňte automatickému spuštění aplikace přidáním autostart="false" do značky Blazor<script> (umístění spuštění skriptu Blazor). Ručně vytvořte adresu URL okruhu pomocí Blazor.start. Následující příklady používají cestu /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>

Do souboru MapBlazorHub v serverové aplikaci přidejte následující volání Program s cestou k hubu do zpracování middlewaru.

Blazor Web Apps:

app.MapBlazorHub("/signalr");

Blazor Server:

Ponechte stávající volání MapBlazorHub v souboru a přidejte nové volání MapBlazorHub se specifikovanou cestou:

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

Zosobnění pro ověřování systému Windows

Ověřená připojení rozbočovače (HubConnection) se vytvářejí s UseDefaultCredentials, které označuje použití výchozích přihlašovacích údajů pro požadavky HTTP. Další informace najdete v tématu Ověřování a autorizace v ASP.NET Core SignalR.

Když aplikace běží ve službě IIS Express jako přihlášený uživatel v rámci ověřování systému Windows, což je pravděpodobně osobní nebo pracovní účet uživatele, výchozí přihlašovací údaje jsou přihlašovací údaje přihlášeného uživatele.

Když je aplikace publikovaná ve službě IIS, spustí se ve fondu aplikací Identity. HubConnection se připojí jako účet "uživatel" služby IIS, který je hostitelem aplikace, nikoli jako uživatel, který ke stránce přistupuje.

Implementujte zosobnění s HubConnection, aby se použila identita procházejícího uživatele.

V následujícím příkladu:

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

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

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

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

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

V předchozím kódu je NavManagerNavigationManagera AuthenticationStateProvider je služební instance AuthenticationStateProvider (AuthenticationStateProvider dokumentace).

Další prostředky na straně serveru