namespace ZB.MOM.WW.OtOpcUa.AdminUI.Hubs; /// /// Raises a multicast delegate one subscriber at a time, so a subscriber that throws cannot stop /// delivery to the subscribers after it. The in-process stores and broadcasters raise their events on /// the bridge actor's thread; a plain handler?.Invoke(x) stops at the first throwing handler (for /// example a Blazor circuit whose renderer is mid-teardown), so the remaining panels miss the update and /// the exception escapes into the bridge actor, which restarts it. /// internal static class SafeMulticast { /// Invokes every subscriber of with , isolating failures. /// The event payload type. /// The captured multicast delegate; null means no subscribers. /// The payload passed to each subscriber. /// Optional sink for a subscriber's exception; it must not throw. /// The number of subscribers that threw. public static int Invoke(Action? handler, T arg, Action? onError = null) { if (handler is null) return 0; var failures = 0; foreach (var subscriber in handler.GetInvocationList()) { try { ((Action)subscriber)(arg); } catch (Exception ex) { failures++; try { onError?.Invoke(ex); } catch { /* the error sink must never take delivery down with it */ } } } return failures; } }