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

  • JsonExceptionFilter cattura ogni eccezione di MetaService.* (e dell'AsmxProxy in generale) e produce un envelope JSON { ok:false, errorCode, args, traceId, fallbackMessage }.
  • MetaExceptionTranslator mappa eccezioni note (es. JsonReaderExceptionerrors.metadata.props_bag.malformed, OperationDisabledExceptionerrors.auth.operation_disabled, SqlExceptionerrors.db.sql_exception con passthrough completo).
  • Il fallback generico e' errors.server.unhandled con traceId per correlazione log.

Lato client (wuic-framework-lib):

  • GlobalHandler (implementa ErrorHandler di 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 / wrapArchetypeLifecycleSync sono helper per wrappare codice JS proveniente da metadata utente (callback, archetype lifecycle) con typed envelope automatico.
  • Le traduzioni vengono caricate dalla tabella _wuic_translations via TranslationManagerService (cache localStorage) e supportano placeholder {argName} interpolati direttamente dal GlobalHandler.
  • BehaviorSubject GlobalHandler.messageNotification emette ogni eccezione gia' tipizzata e localizzata: il consumer si aggancia qui per renderizzare il dialog (vedi app.component.ts di esempio).

Wiring tipico nel consumer (app.config.ts):

Snippet 1ts
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.

Snippet 2ts
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.

Snippet 3ts
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:

Snippet 4ts
// 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:

Snippet 5ts
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:

Snippet 6SQL
-- 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.

Snippet 7C#
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 errorCode applicativi (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.