using System; using System.Collections.Generic; using System.Text; using System.Threading; namespace MT.Platform.Common { /// /// Application specific Notification Broker message handler delegate. /// /// /// public delegate void NotificationHandler(object sender, Notification notification); /// /// Subscriber using in-AppDomain communication via delegates. /// public class LocalSubscription : Subscription { /// /// Constructor /// /// type of notification this subscriber is interested to receive /// notification message filter defining rules for filter in or out of messages /// (Multicast-)Delegate to invoke for notification delivery public LocalSubscription(Type type, NotificationHandler handler, IList filters) : base(type, filters) { lock (LockObject) { this.handler = handler; } } private NotificationHandler handler; /// /// Delegate to invoke when a notification of a desired type arrives. /// public NotificationHandler Handler { get { lock (LockObject) { return handler; } } } /// /// Safely invoke delegates to fire notification. Done on a separate thread pool thread. /// /// public override void Send(Notification notification) { // Broadcast messages individually Delegate[] invocationList = null; lock (LockObject) { if (this.Handler == null) return; invocationList = (Delegate[])this.Handler.GetInvocationList().Clone(); } // If not a multicast delegate, then invoke in this thread, as Subscriptions.Fire already // scheduled invocation onto a separate thread from the one calling ServiceAccessor.GetService().Fire() if (invocationList.Length == 1) { // singlecast delegate (only 1 handler). Call directly from this thread pool thread. // For performance reasons do not switch to yet another thread. invocationList[0].DynamicInvoke(this, notification); } else { // Invoke every delegate separately to allow for exception handling. // Otherwise following handlers are not invoked. foreach (NotificationHandler oneNotiticationHandler in invocationList) { try { ThreadPool.QueueUserWorkItem(delegate(object state) { NotificationHandler handler = state as NotificationHandler; // invoke one separate invocation handler on pool thread to decouple. handler(this, notification); }, oneNotiticationHandler); } catch (Exception ex) { throw new NotImplementedException("One of the multicast delegate invocations on " + "subscription handlers failed. Decide on actions in this catch block!", ex); } } } } } }