Overview

Custom Exception Handling (consumer)

The WUIC framework ships with typed, localized exception handling out of the box. The consumer can extend it to add telemetry, suppress known noise, or emit application-level errors — without rewriting the flow.

Current architecture (summary)

Server side (KonvergenceCore):

  • JsonExceptionFilter catches every MetaService.* (and AsmxProxy in general) exception and produces a JSON envelope { ok:false, errorCode, args, traceId, fallbackMessage }.
  • MetaExceptionTranslator maps known exceptions (e.g. JsonReaderExceptionerrors.metadata.props_bag.malformed, OperationDisabledExceptionerrors.auth.operation_disabled, SqlExceptionerrors.db.sql_exception with full passthrough).
  • The generic fallback is errors.server.unhandled with a traceId for log correlation.

Client side (wuic-framework-lib):

  • GlobalHandler (implements Angular's ErrorHandler) is the central dispatcher. Branches in order: SQL passthrough → typed client exceptions → typed server envelope → NG04002 routing → template runtime errors → legacy → fallback.
  • WtoolboxService.runUserCallback / runUserCallbackSync / wrapArchetypeLifecycleSync are helpers to wrap user-supplied JS coming from metadata (callbacks, archetype lifecycle) with automatic typed envelopes.
  • Translations are loaded from _wuic_translations via TranslationManagerService (localStorage cache) and support {argName} placeholders interpolated by GlobalHandler.
  • The BehaviorSubject GlobalHandler.messageNotification emits each typed and localized exception: the consumer subscribes here to render the dialog (see the app.component.ts example).

Typical wiring in the consumer (app.config.ts):

Snippet 1ts
import { GlobalHandler } from './wuic-bridges/core';

providers: [
  ...
  { provide: ErrorHandler, useClass: GlobalHandler },
  ...
]

Extension points

Pattern 1 — Subscribe (cross-cutting telemetry, RECOMMENDED)

Add a second subscriber to GlobalHandler.messageNotification next to the dialog one. Lets you forward each (already-typed, already-localized) exception to a custom analytics/logging system.

Snippet 2ts
import { GlobalHandler } from './wuic-bridges/core';

GlobalHandler.messageNotification.subscribe((data) => {
  const exc = data?.exception;
  if (!exc?.errorCode) return;

  // Filter known noise.

Pros:

  • Doesn't alter the framework flow.
  • Add/remove without DI wiring changes.
  • Receives the exception AFTER typing (errorCode + args interpolated).

Pattern 2 — Subclass GlobalHandler (override handleError)

When you need to act BEFORE the framework decides what to do: filter known non-actionable errors, enrich args with app context (build version, user role), convert a generic error into a typed one.

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 non-actionable noise.

Wiring:

Snippet 4ts
// app.config.ts
import { MyCustomErrorHandler } from './exception-handling/custom-error-handler.example';

providers: [
  ...
  { provide: ErrorHandler, useClass: MyCustomErrorHandler },
  ...

Pros:

  • Full control over the entry point.
  • Keeps all framework logic by calling super.handleError(e).

Caveat:

  • If you DO NOT call super.handleError, you lose typed envelopes — only use Pattern 3 if truly necessary.

Pattern 3 — Full replace (NOT RECOMMENDED)

Implementing ErrorHandler from scratch without extending GlobalHandler disables ALL built-in features: translations, typed envelopes, SQL passthrough, dedicated dialogs, NG04002 routing, dynamic-template error tagging. Only use it for very specific requirements where you're prepared to re-implement the end-to-end flow.

Pattern 4 — Throw typed exceptions from consumer code

The consumer can EMIT its own typed exceptions that receive the same treatment (translation + dialog) as framework exceptions. Import WuicClientException and throw with your own application errorCode:

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

Add the translations for errors.myapp.feature_disabled to your _wuic_translations seed (at least it-IT + en-US, plus other supported locales). From that point on any throw produces a localized dialog with no further wiring:

Snippet 6SQL
-- Example seed (idempotent, see 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.");

The {feature} placeholder is automatically interpolated from the args passed to the WuicClientException.

Server-side exceptions from consumer code

On the server (consumer controller/service) the pattern is analogous: throw a WuicException from the framework namespace and the JsonExceptionFilter produces the typed JSON envelope that the client localizes.

Snippet 7C#
using WEB_UI_CRAFTER.Helpers.Exceptions;

if (!_myService.IsLicensed("export-pdf"))
{
    throw new WuicException(
        "errors.myapp.license.missing",
        new Dictionary<string, object>

HttpStatus controls the response HTTP code; FallbackMessage is shown when the translation is missing.

Complete example in the WuicTest project

A working example covering all 4 patterns (with comments, inline snippets, and example wiring) is available at:

  • WuicTest/wwwroot/src/app/exception-handling/custom-error-handler.example.ts

The file is part of the test consumer project source and contains 4 sections:

1. installCustomTelemetry() — Pattern 1 (subscribe), ready to call from AppComponent.ngOnInit.

2. MyCustomErrorHandler — Pattern 2 (subclass), ready to wire in app.config.ts.

3. Pattern 3 — commented example (NOT recommended).

4. Pattern 4 — WuicClientException throw snippet from app code.

Best practice

  • Prefer Pattern 1 (subscribe) for telemetry/logging — doesn't alter the flow and is easy to remove.
  • Use Pattern 2 (subclass) only when you need to intervene before the default (noise filtering, args enrichment).
  • Never Pattern 3 unless you have specific enterprise requirements — you lose all built-in functionality.
  • Always seed translations for your application errorCodes (at least it-IT + en-US) before releasing to production, otherwise the dialog shows the raw key.
  • Use server-side `traceId` in the translation template (e.g. "Reference: {traceId}") to ease cross-team support diagnostics.