Overview
Gestione eccezioni custom (consumer)
Il framework WUIC fornisce una gestione eccezioni tipizzata e localizzata pronta all'uso. Il consumer puo' estenderla per aggiungere telemetria, filtrare rumore noto o emettere errori applicativi propri — senza riscrivere il flusso.
Architettura attuale (riassunto)
Lato server (KonvergenceCore):
JsonExceptionFiltercattura ogni eccezione diMetaService.*(e dell'AsmxProxy in generale) e produce un envelope JSON{ ok:false, errorCode, args, traceId, fallbackMessage }.MetaExceptionTranslatormappa eccezioni note (es.JsonReaderException→errors.metadata.props_bag.malformed,OperationDisabledException→errors.auth.operation_disabled,SqlException→errors.db.sql_exceptioncon passthrough completo).- Il fallback generico e'
errors.server.unhandledcontraceIdper correlazione log.
Lato client (wuic-framework-lib):
GlobalHandler(implementaErrorHandlerdi Angular) e' il dispatcher centrale. Branch ordinati: SQL passthrough → typed exceptions client → typed envelope server → NG04002 routing → template runtime errors → legacy → fallback.WtoolboxService.runUserCallback/runUserCallbackSync/wrapArchetypeLifecycleSyncsono helper per wrappare codice JS proveniente da metadata utente (callback, archetype lifecycle) con typed envelope automatico.- Le traduzioni vengono caricate dalla tabella
_wuic_translationsviaTranslationManagerService(cache localStorage) e supportano placeholder{argName}interpolati direttamente dalGlobalHandler. BehaviorSubject GlobalHandler.messageNotificationemette ogni eccezione gia' tipizzata e localizzata: il consumer si aggancia qui per renderizzare il dialog (vediapp.component.tsdi esempio).
Wiring tipico nel consumer (app.config.ts):
import { GlobalHandler } from './wuic-bridges/core';
providers: [
...
{ provide: ErrorHandler, useClass: GlobalHandler },
...
]Punti di estensione
Pattern 1 — Subscribe (cross-cutting telemetry, CONSIGLIATO)
Aggancia un secondo subscriber a GlobalHandler.messageNotification accanto a quello del dialog. Permette di inviare ogni eccezione (gia' tipizzata, gia' localizzata) a un sistema di analytics o logging custom.
import { GlobalHandler } from './wuic-bridges/core';
GlobalHandler.messageNotification.subscribe((data) => {
const exc = data?.exception;
if (!exc?.errorCode) return;
// Filtra rumore noto.Vantaggi:
- Non altera il flusso del framework.
- Si aggiunge/rimuove senza tocchi al wiring DI.
- Riceve l'eccezione DOPO la tipizzazione (errorCode + args interpolati).
Pattern 2 — Subclass GlobalHandler (override handleError)
Quando serve intervenire PRIMA che il framework decida cosa fare con l'errore: filtrare errori noti non azionabili, arricchire args con context applicativo (versione build, ruolo utente), convertire un errore generico in tipizzato.
import { ErrorHandler, Injectable } from '@angular/core';
import { GlobalHandler } from './wuic-bridges/core';
@Injectable()
export class MyCustomErrorHandler extends GlobalHandler {
override handleError(e: any): void {
// 1. Suppress noise non azionabile.Wiring:
// app.config.ts
import { MyCustomErrorHandler } from './exception-handling/custom-error-handler.example';
providers: [
...
{ provide: ErrorHandler, useClass: MyCustomErrorHandler },
...Vantaggi:
- Pieno controllo sul punto di entry.
- Mantiene tutta la logica del framework chiamando
super.handleError(e).
Attenzione:
- Se NON chiami
super.handleError, perdi le typed envelopes — usa Pattern 3 solo se davvero necessario.
Pattern 3 — Replace completo (NON CONSIGLIATO)
Implementare ErrorHandler da zero senza estendere GlobalHandler disabilita TUTTE le funzionalita' built-in: traduzioni, typed envelopes, SQL passthrough, dialog dedicati, NG04002 routing, error-tagging dei dynamic template. Usare solo se hai requisiti molto specifici e sei pronto a re-implementare il flusso end-to-end.
Pattern 4 — Throw eccezioni tipizzate dal codice consumer
Il consumer puo' EMETTERE eccezioni tipizzate proprie che riceveranno lo stesso trattamento (traduzione + dialog) delle eccezioni del framework. Importa WuicClientException e lancia con il tuo errorCode applicativo:
import { WuicClientException } from 'wuic-framework-lib-src/exception/WuicClientException';
if (!myConfig.exportEnabled) {
throw new WuicClientException(
'errors.myapp.feature_disabled',
{ feature: 'export-pdf' },
{ surface: 'service', targetName: 'MyAppService.exportPdf' }Aggiungi le traduzioni errors.myapp.feature_disabled nel tuo seed di _wuic_translations (it-IT + en-US e gli altri locale supportati). Da quel momento qualunque throw produrra' un dialog localizzato senza ulteriore wiring:
-- Esempio seed (idempotente, vedi scripts/upsert-wuic-translations.ps1).
INSERT INTO _wuic_translations (translation_key, locale, translation_text)
VALUES
('errors.myapp.feature_disabled', 'it-IT', "Funzionalita' '{feature}' disabilitata in questa versione."),
('errors.myapp.feature_disabled', 'en-US', "Feature ''{feature}'' is disabled in this build.");Il placeholder {feature} viene interpolato automaticamente dagli args passati alla WuicClientException.
Eccezioni server-side dal codice consumer
Lato server (controller/service consumer) il pattern e' analogo: lancia WuicException dal namespace del framework e il JsonExceptionFilter produce l'envelope JSON tipizzato che il client traduce.
using WEB_UI_CRAFTER.Helpers.Exceptions;
if (!_myService.IsLicensed("export-pdf"))
{
throw new WuicException(
"errors.myapp.license.missing",
new Dictionary<string, object>L'HttpStatus controlla il codice HTTP della risposta; il fallbackMessage viene mostrato se la traduzione manca.
Esempio completo nel progetto WuicTest
Un esempio funzionante con tutti e 4 i pattern (con commenti, snippet inline, e wiring di esempio) e' presente in:
Il file e' incluso nel sorgente del progetto consumer di test e contiene 4 sezioni:
1. installCustomTelemetry() — Pattern 1 (subscribe), pronto da chiamare in AppComponent.ngOnInit.
2. MyCustomErrorHandler — Pattern 2 (subclass), pronto da wirare in app.config.ts.
3. Pattern 3 — esempio commentato (NON consigliato).
4. Pattern 4 — snippet di throw WuicClientException dal codice applicativo.
Best practice
- Privilegia Pattern 1 (subscribe) per telemetria/logging — non altera il flusso e si rimuove facilmente.
- Usa Pattern 2 (subclass) solo se devi intervenire prima del default (filtro rumore, arricchimento args).
- Mai Pattern 3 salvo requisiti enterprise specifici — perdi tutto il built-in.
- Sempre seed le traduzioni dei tuoi
errorCodeapplicativi (it-IT + en-US minimo) prima di rilasciare in produzione, altrimenti il dialog mostra la chiave grezza. - Usa `traceId` server-side nel template di traduzione (es.
"Codice: {traceId}") per facilitare la diagnostica condivisa fra utente e team supporto.