# .NET, Blazor WebAssembly e JS interop

## Indice

1. Render lifecycle
2. JS interop
3. Concorrenza asincrona
4. Disposal
5. Cache e servizi
6. Profilazione WASM

## 1. Render lifecycle

Verifica prima di ottimizzare:

- chi chiama `StateHasChanged` e quante volte;
- se un callback figlio provoca render del parent e di sibling costosi;
- se `OnAfterRenderAsync` esegue interop a ogni render senza version/key guard;
- se una proprietà o collection cambia identità pur avendo contenuto invariato;
- se un dettaglio chiuso continua a renderizzare o viene ricreato a ogni toggle.

Non usare `ShouldRender` come cerotto generale: può congelare stato funzionale. Prima riduci notifiche e identità instabili, poi applica guard mirate e testate.

Per pannelli costosi usati ripetutamente, valuta mount-once + hide dopo la prima apertura. Verifica accessibilità, validation state e cleanup finale.

## 2. JS interop

Tratta ogni chiamata .NET/JS come boundary costoso:

- invia payload minimi e serializzabili;
- accorpa più operazioni nello stesso call quando condividono lifecycle;
- evita chiamate per riga/cella;
- usa version/key per saltare aggiornamenti invariati;
- evita round-trip .NET -> JS -> .NET per eventi ad alta frequenza;
- gestisci `JSDisconnectedException`/disposal secondo lo stack host.

Se usi interop sincrono in WASM, limitane l'uso a operazioni piccole e locali; non assumerlo disponibile su altri hosting model.

## 3. Concorrenza asincrona

### Supersession

Per ricerche o option dipendenti da input:

1. sostituisci e disponi la `CancellationTokenSource` precedente;
2. incrementa una generation;
3. costruisci il risultato in una variabile locale;
4. applica solo se generation e lifetime sono ancora correnti;
5. preserva lo stato valido in caso di richiesta superseded o fallita.

### Coalescing

Per refresh ripetute:

- consenti una sola operazione attiva;
- conserva al massimo una trailing request con lo stato più recente;
- propaga l'errore una sola volta;
- cancella cooperativamente l'operazione attiva alla disposal;
- testa richieste durante start, active, trailing, error e disposal.

Per lookup per chiave, condividi il task in-flight della stessa chiave e completa tutti gli awaiter anche quando il risultato è mancante o fallisce.

## 4. Disposal

Un componente che possiede risorse deve disporle nello stesso layer:

- cancellation source e runner;
- subscription a service/event aggregator;
- `DotNetObjectReference`;
- modulo JS o controller associato all'elemento;
- timer e debounce;
- richieste che potrebbero completare dopo navigation.

Non attendere indefinitamente una refresh non cancellabile durante `DisposeAsync`. Introduci cancellation cooperativa e test con operazione bloccata.

## 5. Cache e servizi

Definisci esplicitamente:

- scope (component, scoped service, session, process);
- chiave completa, inclusa lingua/tenant quando necessaria;
- TTL e cardinalità;
- comportamento su errore e missing item;
- invalidazione dopo create/update;
- dedupe in-flight separato dalla cache dei risultati.

Preferisci dedupe in-flight quando il requisito di freshness non autorizza una cache lunga.

## 6. Profilazione WASM

In una build Debug, runtime e symbol overhead possono dominare. Confronta sempre nello stesso tipo di build. Richiedi un profilo con simboli quando una funzione WASM non attribuita supera una soglia materiale (per esempio 500 ms o 20% del main-thread time) dopo aver escluso layout, JS e network.

Non dedurre il metodo managed responsabile dal solo indirizzo WASM. Correlalo con render counter, interop marker, eventi applicativi e simboli della build corrispondente.
