Ospitare e distribuire app lato Blazor server

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Questo articolo illustra come ospitare e distribuire app sul lato Blazor server (BlazorApp Web e Blazor Server app) usando ASP.NET Core.

Valori di configurazione dell'host

Le app lato Blazor server possono accettare valori di configurazione host generici.

Distribuzione

Usando un modello di hosting lato server, Blazor viene eseguito nel server dall'interno di un'app ASP.NET Core. Gli aggiornamenti dell'interfaccia utente, la gestione degli eventi e le chiamate JavaScript vengono gestiti tramite una SignalR connessione.

È necessario un server Web in grado di ospitare un'app ASP.NET Core. Visual Studio include un modello di progetto app sul lato server. Per altre informazioni sui Blazor modelli di progetto, vedere ASP.NET struttura del progetto CoreBlazor.

Pubblicare un'app nella configurazione della versione e distribuire il contenuto della bin/Release/{TARGET FRAMEWORK}/publish cartella, in cui il {TARGET FRAMEWORK} segnaposto è il framework di destinazione.

Scalabilità

Quando si considera la scalabilità di un singolo server (aumento delle prestazioni), è probabile che la memoria disponibile per un'app sia la prima risorsa esaurita dall'app man mano che l'utente richiede un aumento. La memoria disponibile nel server influisce su:

  • Numero di circuiti attivi che un server può supportare.
  • Latenza dell'interfaccia utente nel client.

Per indicazioni sulla creazione di app lato Blazor server sicure e scalabili, vedere le risorse seguenti:

Ogni circuito usa circa 250 KB di memoria per un'app di tipo Hello World minima. Le dimensioni di un circuito dipendono dal codice dell'app e dai requisiti di manutenzione dello stato associati a ogni componente. Ti consigliamo di misurare le richieste di risorse durante lo sviluppo per l'app e l'infrastruttura, ma la baseline seguente può essere un punto di partenza nella pianificazione della destinazione di distribuzione: se prevedi che l'app supporti 5.000 utenti simultanei, valuta la possibilità di budget di almeno 1,3 GB di memoria server per l'app (o circa 273 KB per utente).

Configurazione SignalR

SignalRLe condizioni di hosting e ridimensionamento si applicano alle Blazor app che usano SignalR.

Per altre informazioni sulle app, incluse le linee guida sulla SignalR configurazione, vedere ASP.NET Linee guida di baseBlazorSignalR.Blazor

Trasporti

Blazor funziona meglio quando si usano WebSocket come SignalR trasporto a causa di una latenza inferiore, maggiore affidabilità e maggiore sicurezza. Il polling lungo viene usato da SignalR quando WebSocket non è disponibile o quando l'app è configurata in modo esplicito per l'uso del polling lungo. Quando si esegue la distribuzione nel servizio app Azure, configurare l'app per l'uso di WebSocket nelle impostazioni di portale di Azure per il servizio. Per informazioni dettagliate sulla configurazione dell'app per app Azure Service, vedere le linee guida per la SignalR pubblicazione.

Viene visualizzato un avviso della console se viene utilizzato long polling:

Impossibile connettersi tramite WebSocket, utilizzando il trasporto di fallback di polling lungo. Ciò può essere dovuto a una VPN o a un proxy che blocca la connessione.

Errori di distribuzione e connessione globali

Consigli per le distribuzioni globali nei data center geografici:

  • Distribuire l'app nelle aree in cui risiede la maggior parte degli utenti.
  • Prendere in considerazione l'aumento della latenza per il traffico in tutti i continenti. Per controllare l'aspetto dell'interfaccia utente di riconnessione, vedere ASP.NET Linee guida di baseBlazorSignalR.
  • Per l'hosting di Azure, usare il servizio di AzureSignalR.

Servizio di Azure SignalR

Per Blazor App Web che adottano il rendering lato server interattivo, è consigliabile usare il servizio di AzureSignalR. Il servizio funziona insieme all'hub dell'app Blazor per aumentare fino a un numero elevato di connessioni simultanee SignalR . Inoltre, la copertura globale del servizio e i data center ad alte prestazioni aiutano significativamente a ridurre la latenza a causa della geografia. Se l'ambiente di hosting gestisce già questi problemi, l'uso del servizio di Azure SignalR non è necessario.

Nota

La riconnessione con stato (WithStatefulReconnect) è stata rilasciata con .NET 8, ma non è attualmente supportata per il servizio di Azure SignalR . Per altre informazioni, vedere Supporto della riconnessione con stato? (Azure/azure-signalr n. 1878)..

È consigliabile usare il servizio di AzureSignalR, che funziona insieme all'hub dell'app Blazor per aumentare le prestazioni fino a un numero elevato di connessioni simultaneeSignalR. Inoltre, la copertura globale del servizio e i data center ad alte prestazioni aiutano significativamente a ridurre la latenza a causa della geografia. Se l'ambiente di hosting gestisce già questi problemi, l'uso del servizio di Azure SignalR non è necessario.

Importante

Quando i WebSocket sono disabilitati, app Azure Servizio simula una connessione in tempo reale usando http long polling. Il polling lungo HTTP è notevolmente più lento rispetto all'esecuzione con WebSocket abilitato, che non usa il polling per simulare una connessione client-server. Nel caso in cui sia necessario usare il polling lungo, potrebbe essere necessario configurare l'intervallo di polling massimo (MaxPollIntervalInSeconds), che definisce l'intervallo di polling massimo consentito per le connessioni di polling lungo nel servizio di Azure SignalR se il servizio esegue il fallback da WebSocket a Long Polling. Se la richiesta di polling successiva non entra in MaxPollIntervalInSeconds, il servizio di Azure SignalR pulisce la connessione client. Si noti che il servizio di Azure SignalR pulisce anche le connessioni quando vengono memorizzate nella cache in attesa di dimensioni del buffer di scrittura è maggiore di 1 MB per garantire le prestazioni del servizio. Il valore predefinito per MaxPollIntervalInSeconds è 5 secondi. L'impostazione è limitata a 1-300 secondi.

È consigliabile usare WebSocket per le app lato Blazor server distribuite nel servizio app Azure. Il servizio di Azure SignalR usa WebSocket per impostazione predefinita. Se l'app non usa il servizio di AzureSignalR, vedere Pubblicare un'app ASP.NET Core SignalR nel servizio app Azure.

Per altre informazioni, vedi:

Impostazione

Per configurare un'app per il servizio di Azure SignalR , l'app deve supportare sessioni permanenti, in cui i client vengono reindirizzati allo stesso server durante la pre-gestione. L'opzione ServerStickyMode o il valore di configurazione è impostato su Required. In genere, un'app crea la configurazione usando uno degli approcci seguenti:

  • Program.cs:

    builder.Services.AddSignalR().AddAzureSignalR(options =>
    {
        options.ServerStickyMode = 
            Microsoft.Azure.SignalR.ServerStickyMode.Required;
    });
    
  • Configurazione (usare uno degli approcci seguenti):

    • In appsettings.json:

      "Azure:SignalR:ServerStickyMode": "Required"
      
    • Impostazioni dell'applicazione di configurazione>del servizio app nel portale di Azure (nome: Azure__SignalR__ServerStickyMode, valore: Required). Questo approccio viene adottato automaticamente per l'app se si effettua il provisioning del servizio di AzureSignalR.

Nota

L'errore seguente viene generato da un'app che non ha abilitato sessioni permanenti per il servizio di Azure SignalR :

blazor.server.js:1 Errore non rilevato (in promessa): chiamata annullata a causa della chiusura della connessione sottostante.

Effettuare il provisioning del servizio di Azure SignalR

Per effettuare il provisioning del servizio di Azure SignalR per un'app in Visual Studio:

  1. Creare un profilo di pubblicazione di app Azure in Visual Studio per l'app.
  2. Aggiungere la dipendenza del servizio di Azure SignalR al profilo. Se la sottoscrizione di Azure non ha un'istanza del servizio di Azure SignalR preesistente da assegnare all'app, selezionare Crea una nuova istanza del servizio di Azure SignalR per effettuare il provisioning di una nuova istanza del servizio.
  3. Pubblicare l'app in Azure.

Il provisioning del servizio di Azure SignalR in Visual Studio abilita automaticamente le sessioni permanenti e aggiunge il SignalR stringa di connessione alla configurazione del servizio app.

Scalabilità nelle app Azure Container

Il ridimensionamento delle app sul lato Blazor server in App Azure Container richiede considerazioni specifiche oltre all'uso del servizio di AzureSignalR. A causa del modo in cui viene gestito il routing delle richieste, il servizio di protezione dati core di ASP.NET deve essere configurato per rendere persistenti le chiavi in una posizione centralizzata a cui tutte le istanze del contenitore possono accedere. Le chiavi possono essere archiviate in Archiviazione BLOB di Azure e protette con Azure Key Vault. Il servizio protezione dati usa le chiavi per deserializzare i Razor componenti.

Nota

Per un'esplorazione più approfondita di questo scenario e del ridimensionamento delle app contenitore, vedere Ridimensionamento delle app di base ASP.NET in Azure. L'esercitazione illustra come creare e integrare i servizi necessari per ospitare app in App Azure Container. In questa sezione vengono forniti anche i passaggi di base.

  1. Per configurare il servizio di protezione dei dati per l'uso di Archiviazione BLOB di Azure e Azure Key Vault, fare riferimento ai pacchetti NuGet seguenti:

    Nota

    Per indicazioni sull'aggiunta di pacchetti alle app .NET, vedere gli articoli sotto Installare e gestire pacchetti in Flusso di lavoro dell'utilizzo di pacchetti (documentazione di NuGet). Confermare le versioni corrette del pacchetto all'indirizzo NuGet.org.

  2. Eseguire l'aggiornamento Program.cs con il codice evidenziato seguente:

    using Azure.Identity;
    using Microsoft.AspNetCore.DataProtection;
    using Microsoft.Extensions.Azure;
    
    var builder = WebApplication.CreateBuilder(args);
    var BlobStorageUri = builder.Configuration["AzureURIs:BlobStorage"];
    var KeyVaultURI = builder.Configuration["AzureURIs:KeyVault"];
    
    builder.Services.AddRazorPages();
    builder.Services.AddHttpClient();
    builder.Services.AddServerSideBlazor();
    
    builder.Services.AddAzureClientsCore();
    
    builder.Services.AddDataProtection()
                    .PersistKeysToAzureBlobStorage(new Uri(BlobStorageUri),
                                                    new DefaultAzureCredential())
                    .ProtectKeysWithAzureKeyVault(new Uri(KeyVaultURI),
                                                    new DefaultAzureCredential());
    var app = builder.Build();
    
    if (!app.Environment.IsDevelopment())
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }
    
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapRazorPages();
    
    app.Run();
    

    Le modifiche precedenti consentono all'app di gestire la protezione dei dati usando un'architettura centralizzata e scalabile. DefaultAzureCredential individua l'identità gestita dell'app contenitore dopo la distribuzione del codice in Azure e la usa per connettersi all'archiviazione BLOB e all'insieme di credenziali delle chiavi dell'app.

  3. Per creare l'identità gestita dell'app contenitore e concedergli l'accesso all'archiviazione BLOB e a un insieme di credenziali delle chiavi, seguire questa procedura:

    1. Nel portale di Azure passare alla pagina di panoramica dell'app contenitore.
    2. Selezionare Service Connessione or (Service Connessione or) nel riquadro di spostamento sinistro.
    3. Selezionare + Crea nella barra di spostamento superiore.
    4. Nel menu a comparsa Crea connessione immettere i valori seguenti:
      • Contenitore: selezionare l'app contenitore creata per ospitare l'app.
      • Tipo di servizio: selezionare Blob Archiviazione.
      • Sottoscrizione: selezionare la sottoscrizione proprietaria dell'app contenitore.
      • nome Connessione ion: immettere un nome .scalablerazorstorage
      • Tipo di client: selezionare .NET e quindi selezionare Avanti.
    5. Selezionare Identità gestita assegnata dal sistema e selezionare Avanti.
    6. Usare le impostazioni di rete predefinite e selezionare Avanti.
    7. Dopo che Azure convalida le impostazioni, selezionare Crea.

    Ripetere le impostazioni precedenti per l'insieme di credenziali delle chiavi. Selezionare il servizio e la chiave dell'insieme di credenziali delle chiavi appropriati nella scheda Informazioni di base .

app Azure Servizio senza Azure SignalR Servizio

L'hosting di un'app Blazor Web che usa il rendering lato server interattivo in app Azure Servizio richiede la configurazione per l'affinità ARR (Application Request Routing) e WebSocket. Il servizio app deve anche essere distribuito a livello globale in modo appropriato per ridurre la latenza dell'interfaccia utente. L'uso del servizio di Azure SignalR quando si ospita nel servizio app Azure non è necessario.

L'hosting di un'app Blazor Server nel servizio app Azure richiede la configurazione per l'affinità ARR (Application Request Routing) e WebSocket. Il servizio app deve anche essere distribuito a livello globale in modo appropriato per ridurre la latenza dell'interfaccia utente. L'uso del servizio di Azure SignalR quando si ospita nel servizio app Azure non è necessario.

Usare le indicazioni seguenti per configurare l'app:

IIS

Quando si usa IIS, abilitare:

Per altre informazioni, vedere le linee guida e i collegamenti incrociati delle risorse IIS esterne in Pubblicare un'app ASP.NET Core in IIS.

Kubernetes

Creare una definizione di ingresso con le annotazioni Kubernetes seguenti per le sessioni permanenti:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: <ingress-name>
  annotations:
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "affinity"
    nginx.ingress.kubernetes.io/session-cookie-expires: "14400"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "14400"

Linux con Nginx

Seguire le indicazioni per un'app ASP.NET Core SignalR con le modifiche seguenti:

  • Modificare il location percorso da /hubroute (location /hubroute { ... }) al percorso / radice (location / { ... }).
  • Rimuovere la configurazione per il buffering proxy (proxy_buffering off;) perché l'impostazione si applica solo agli eventi inviati dal server (S edizione Standard), che non sono rilevanti per Blazor le interazioni client-server dell'app.

Per altre informazioni e indicazioni sulla configurazione, vedere le risorse seguenti:

Linux con Apache

Per ospitare un'app Blazor dietro Apache in Linux, configurare ProxyPass per il traffico HTTP e WebSocket.

Nell'esempio seguente :

  • Kestrel server è in esecuzione nel computer host.
  • L'app rimane in ascolto del traffico sulla porta 5000.
ProxyPreserveHost   On
ProxyPassMatch      ^/_blazor/(.*) http://localhost:5000/_blazor/$1
ProxyPass           /_blazor ws://localhost:5000/_blazor
ProxyPass           / http://localhost:5000/
ProxyPassReverse    / http://localhost:5000/

Abilitare i moduli seguenti:

a2enmod   proxy
a2enmod   proxy_wstunnel

Controllare la presenza di errori webSocket nella console del browser. Errori di esempio:

  • Firefox non riesce a stabilire una connessione al server all'indirizzo ws://the-domain-name.tld/_blazor?id=XXX
  • Errore: Impossibile avviare il trasporto 'WebSockets': Errore: Errore: Errore: errore con il trasporto.
  • Errore: Impossibile avviare il trasporto 'LongPolling': TypeError: this.transport non è definito
  • Errore: impossibile connettersi al server con uno dei trasporti disponibili. WebSocket non riuscito
  • Errore: impossibile inviare dati se la connessione non è nello stato 'Connessione ed'.

Per altre informazioni e indicazioni sulla configurazione, vedere le risorse seguenti:

Misurare la latenza di rete

JS l'interoperabilità può essere usata per misurare la latenza di rete, come illustrato nell'esempio seguente.

MeasureLatency.razor:

@inject IJSRuntime JS

<h2>Measure Latency</h2>

@if (latency is null)
{
    <span>Calculating...</span>
}
else
{
    <span>@(latency.Value.TotalMilliseconds)ms</span>
}

@code {
    private DateTime startTime;
    private TimeSpan? latency;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            startTime = DateTime.UtcNow;
            var _ = await JS.InvokeAsync<string>("toString");
            latency = DateTime.UtcNow - startTime;
            StateHasChanged();
        }
    }
}
@inject IJSRuntime JS

<h2>Measure Latency</h2>

@if (latency is null)
{
    <span>Calculating...</span>
}
else
{
    <span>@(latency.Value.TotalMilliseconds)ms</span>
}

@code {
    private DateTime startTime;
    private TimeSpan? latency;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            startTime = DateTime.UtcNow;
            var _ = await JS.InvokeAsync<string>("toString");
            latency = DateTime.UtcNow - startTime;
            StateHasChanged();
        }
    }
}
@inject IJSRuntime JS

<h2>Measure Latency</h2>

@if (latency is null)
{
    <span>Calculating...</span>
}
else
{
    <span>@(latency.Value.TotalMilliseconds)ms</span>
}

@code {
    private DateTime startTime;
    private TimeSpan? latency;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            startTime = DateTime.UtcNow;
            var _ = await JS.InvokeAsync<string>("toString");
            latency = DateTime.UtcNow - startTime;
            StateHasChanged();
        }
    }
}
@inject IJSRuntime JS

@if (latency is null)
{
    <span>Calculating...</span>
}
else
{
    <span>@(latency.Value.TotalMilliseconds)ms</span>
}

@code {
    private DateTime startTime;
    private TimeSpan? latency;

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            startTime = DateTime.UtcNow;
            var _ = await JS.InvokeAsync<string>("toString");
            latency = DateTime.UtcNow - startTime;
            StateHasChanged();
        }
    }
}

Per un'esperienza di interfaccia utente ragionevole, è consigliabile una latenza dell'interfaccia utente sostenuta di 250 ms o meno.

Gestione della memoria

Nel server viene creato un nuovo circuito per ogni sessione utente. Ogni sessione utente corrisponde al rendering di un singolo documento nel browser. Ad esempio, più schede creano più sessioni.

Blazor mantiene una connessione costante al browser, denominata circuito, che ha avviato la sessione. Connessione ioni possono andare perse in qualsiasi momento per diversi motivi, ad esempio quando l'utente perde la connettività di rete o chiude bruscamente il browser. Quando una connessione viene persa, Blazor dispone di un meccanismo di ripristino che inserisce un numero limitato di circuiti in un pool "disconnesso", offrendo ai client una quantità limitata di tempo per riconnettersi e ristabilire la sessione (impostazione predefinita: 3 minuti).

Successivamente, Blazor rilascia il circuito ed elimina la sessione. Da questo punto in poi, il circuito è idoneo per l'operazione di Garbage Collection (GC) e viene richiesto quando viene attivata una raccolta per la generazione GC del circuito. Un aspetto importante da comprendere è che i circuiti hanno una lunga durata, il che significa che la maggior parte degli oggetti radicati dal circuito alla fine raggiunge la generazione 2. Di conseguenza, è possibile che tali oggetti non vengano rilasciati fino a quando non si verifica una raccolta di generazione 2.

Misurare l'utilizzo della memoria in generale

Prerequisiti:

  • L'app deve essere pubblicata nella configurazione della versione . Le misurazioni della configurazione di debug non sono rilevanti, perché il codice generato non è rappresentativo del codice usato per una distribuzione di produzione.
  • L'app deve essere eseguita senza un debugger collegato, perché ciò potrebbe influire anche sul comportamento dell'app e rovinare i risultati. In Visual Studio avviare l'app senza eseguire il debug selezionando Avvia debug>senza eseguire debug dalla barra dei menu o CTRL+F5 usando la tastiera.
  • Prendere in considerazione i diversi tipi di memoria per comprendere la quantità di memoria effettivamente usata da .NET. In genere, gli sviluppatori controllano l'utilizzo della memoria delle app in Gestione attività nel sistema operativo Windows, che in genere offre un limite superiore della memoria effettiva in uso. Per altre informazioni, vedere gli articoli seguenti:

Utilizzo della memoria applicato a Blazor

La memoria usata da blazor viene calcolata come segue:

(Circuiti attivi × memoria per circuito) + (circuiti disconnessi × memoria per circuito)

La quantità di memoria usata da un circuito e il massimo potenziale circuito attivo che un'app può gestire dipende in gran parte dal modo in cui viene scritta l'app. Il numero massimo di possibili circuiti attivi è descritto approssimativamente da:

Numero massimo di circuiti attivi per memoria disponibile / per circuito =

Affinché si verifichi una perdita di memoria in Blazor, è necessario che sia true quanto segue:

  • La memoria deve essere allocata dal framework, non dall'app. Se si alloca una matrice di 1 GB nell'app, l'app deve gestire l'eliminazione della matrice.
  • La memoria non deve essere usata attivamente, il che significa che il circuito non è attivo ed è stato rimosso dalla cache dei circuiti disconnessi. Se sono in esecuzione i circuiti attivi massimi, l'esaurimento della memoria è un problema di scalabilità, non una perdita di memoria.
  • È stata eseguita una Garbage Collection (GC) per la generazione GC del circuito, ma il Garbage Collector non è riuscito a richiedere il circuito perché un altro oggetto nel framework contiene un riferimento sicuro al circuito.

In altri casi, non c'è perdita di memoria. Se il circuito è attivo (connesso o disconnesso), il circuito è ancora in uso.

Se non viene eseguita una raccolta per la generazione GC del circuito, la memoria non viene rilasciata perché il Garbage Collector non deve liberare la memoria in quel momento.

Se una raccolta per una generazione GC viene eseguita e libera il circuito, è necessario convalidare la memoria rispetto alle statistiche GC, non il processo, in quanto .NET potrebbe decidere di mantenere attiva la memoria virtuale.

Se la memoria non viene liberata, è necessario trovare un circuito che non sia attivo o disconnesso e che sia rooted da un altro oggetto nel framework. In qualsiasi altro caso, l'impossibilità di liberare memoria è un problema dell'app nel codice per sviluppatori.

Ridurre l'utilizzo della memoria

Adottare una delle strategie seguenti per ridurre l'utilizzo della memoria di un'app:

  • Limitare la quantità totale di memoria usata dal processo .NET. Per altre informazioni, vedere Opzioni di configurazione del runtime per Garbage Collection.
  • Ridurre il numero di circuiti disconnessi.
  • Ridurre il tempo in cui un circuito può trovarsi nello stato disconnesso.
  • Attivare manualmente un'operazione di Garbage Collection per eseguire una raccolta durante i periodi di inattività.
  • Configurare l'operazione di Garbage Collection in modalità workstation, che attiva in modo aggressivo la Garbage Collection anziché la modalità Server.

Dimensioni dell'heap per alcuni browser per dispositivi mobili

Quando si compila un'app Blazor eseguita nel client e si rivolge ai browser per dispositivi mobili, in particolare Safari in iOS, è possibile che sia necessaria una riduzione della memoria massima per l'app con la proprietà EmccMaximumHeapSize MSBuild. Per altre informazioni, vedere Ospitare e distribuire ASP.NET Core Blazor WebAssembly.

Azioni e considerazioni aggiuntive

  • Acquisire un dump di memoria del processo quando le richieste di memoria sono elevate e identificare gli oggetti che stanno occupando la maggior parte della memoria e dove si trovano tali oggetti sono rooted (ciò che contiene un riferimento a tali oggetti).
  • È possibile esaminare le statistiche sul comportamento della memoria nell'app usando dotnet-counters. Per altre informazioni, vedere Analizzare i contatori delle prestazioni (dotnet-counters).
  • Anche quando viene attivato un GC, .NET mantiene la memoria invece di restituirla immediatamente al sistema operativo, perché è probabile che riutilizzi la memoria nel prossimo futuro. In questo modo si evita il commit e il decommettimento costante della memoria, che è costoso. Si noterà che ciò si riflette se si usa dotnet-counters perché si noterà che i controller di dominio vengono eseguiti e la quantità di memoria usata scende a 0 (zero), ma non si noterà la riduzione del contatore del set di lavoro, ovvero il segno che .NET è in possesso della memoria per riutilizzarla. Per altre informazioni sulle impostazioni del file di progetto (.csproj) per controllare questo comportamento, vedere Opzioni di configurazione del runtime per Garbage Collection.
  • Server GC non attiva Garbage Collection finché non determina che è assolutamente necessario farlo per evitare di bloccare l'app e considera che l'app è l'unica cosa in esecuzione nel computer, in modo che possa usare tutta la memoria nel sistema. Se il sistema ha 50 GB, il Garbage Collector cerca di usare l'intero 50 GB di memoria disponibile prima di attivare una raccolta di generazione 2.
  • Per informazioni sulla configurazione di conservazione dei circuiti disconnessi, vedere ASP.NET Linee guida di baseBlazorSignalR.

Misurazione della memoria

  • Pubblicare l'app nella configurazione della versione.
  • Eseguire una versione pubblicata dell'app.
  • Non collegare un debugger all'app in esecuzione.
  • L'attivazione di una raccolta forzata di generazione 2 compattazione (GC.Collect(2, GCCollectionMode.Aggressive | GCCollectionMode.Forced, blocking: true, compacting: true)) liberare la memoria?
  • Valutare se l'app sta allocando oggetti nell'heap di oggetti di grandi dimensioni.
  • Si sta testando la crescita della memoria dopo che l'app viene riscaldata con richieste ed elaborazione? In genere, sono presenti cache popolate durante l'esecuzione del codice per la prima volta che aggiungono una quantità costante di memoria al footprint dell'app.