# HG changeset patch # User Steven Robbins # Date 1268483593 0 # Branch messenger # Node ID 2c5f5e48d084b1bbfab25d663374abc6f5dc68f8 # Parent d1a71995aa8149e71a4345b4b2105c17279ee2b9 Added support for custom message proxies for interception and thread marshalling. Default proxy just passes the message through. diff -r d1a71995aa8149e71a4345b4b2105c17279ee2b9 -r 2c5f5e48d084b1bbfab25d663374abc6f5dc68f8 TinyIoC.Tests/TestData/TinyMessengerTestData.cs --- a/TinyIoC.Tests/TestData/TinyMessengerTestData.cs Sat Mar 13 11:21:23 2010 +0000 +++ b/TinyIoC.Tests/TestData/TinyMessengerTestData.cs Sat Mar 13 12:33:13 2010 +0000 @@ -13,4 +13,16 @@ } } + + public class TestProxy : ITinyMessageProxy + { + public ITinyMessage Message {get; private set;} + + public void Deliver(ITinyMessage message, ITinyMessageSubscription subscription) + { + this.Message = message; + subscription.Deliver(message); + } + } + } diff -r d1a71995aa8149e71a4345b4b2105c17279ee2b9 -r 2c5f5e48d084b1bbfab25d663374abc6f5dc68f8 TinyIoC.Tests/TinyMessengerTests.cs --- a/TinyIoC.Tests/TinyMessengerTests.cs Sat Mar 13 11:21:23 2010 +0000 +++ b/TinyIoC.Tests/TinyMessengerTests.cs Sat Mar 13 12:33:13 2010 +0000 @@ -33,7 +33,7 @@ var output = messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction)); - Assert.IsInstanceOfType(output, typeof(TinyMessageSubscription)); + Assert.IsInstanceOfType(output, typeof(TinyMessageSubscriptionToken)); } [TestMethod] @@ -67,7 +67,16 @@ { var messenger = UtilityMethods.GetMessenger(); - messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), null); + messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), null, new TestProxy()); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void Subscribe_NullProxy_Throws() + { + var messenger = UtilityMethods.GetMessenger(); + + messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), new Func(UtilityMethods.FakeMessageFilter), null); } [TestMethod] @@ -99,6 +108,94 @@ } [TestMethod] + public void Subscribe_CustomProxyNoFilter_DoesNotThrow() + { + var messenger = UtilityMethods.GetMessenger(); + var proxy = new TestProxy(); + + messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), proxy); + } + + [TestMethod] + public void Subscribe_CustomProxyWithFilter_DoesNotThrow() + { + var messenger = UtilityMethods.GetMessenger(); + var proxy = new TestProxy(); + + messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), new Func(UtilityMethods.FakeMessageFilter), proxy); + } + + [TestMethod] + public void Subscribe_CustomProxyNoFilterStrongReference_DoesNotThrow() + { + var messenger = UtilityMethods.GetMessenger(); + var proxy = new TestProxy(); + + messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), true, proxy); + } + + [TestMethod] + public void Subscribe_CustomProxyFilterStrongReference_DoesNotThrow() + { + var messenger = UtilityMethods.GetMessenger(); + var proxy = new TestProxy(); + + messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), new Func(UtilityMethods.FakeMessageFilter), true, proxy); + } + + [TestMethod] + public void Publish_CustomProxyNoFilter_UsesCorrectProxy() + { + var messenger = UtilityMethods.GetMessenger(); + var proxy = new TestProxy(); + messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), proxy); + var message = new TestMessage(this); + + messenger.Publish(message); + + Assert.ReferenceEquals(message, proxy.Message); + } + + [TestMethod] + public void Publish_CustomProxyWithFilter_UsesCorrectProxy() + { + var messenger = UtilityMethods.GetMessenger(); + var proxy = new TestProxy(); + messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), new Func(UtilityMethods.FakeMessageFilter), proxy); + var message = new TestMessage(this); + + messenger.Publish(message); + + Assert.ReferenceEquals(message, proxy.Message); + } + + [TestMethod] + public void Publish_CustomProxyNoFilterStrongReference_UsesCorrectProxy() + { + var messenger = UtilityMethods.GetMessenger(); + var proxy = new TestProxy(); + messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), true, proxy); + var message = new TestMessage(this); + + messenger.Publish(message); + + Assert.ReferenceEquals(message, proxy.Message); + } + + [TestMethod] + public void Publish_CustomProxyFilterStrongReference_UsesCorrectProxy() + { + var messenger = UtilityMethods.GetMessenger(); + var proxy = new TestProxy(); + messenger.Subscribe(new Action(UtilityMethods.FakeDeliveryAction), new Func(UtilityMethods.FakeMessageFilter), true, proxy); + var message = new TestMessage(this); + + messenger.Publish(message); + + Assert.ReferenceEquals(message, proxy.Message); + } + + [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void Publish_NullMessage_Throws() { @@ -199,5 +296,13 @@ Assert.AreEqual("Testing", output); } + + [TestMethod] + public void Publish_SubscriptionThrowingException_DoesNotThrow() + { + var messenger = UtilityMethods.GetMessenger(); + messenger.Subscribe>((m) => { throw new NotImplementedException(); }); + messenger.Publish(new GenericTinyMessage(this, "Testing")); + } } } \ No newline at end of file diff -r d1a71995aa8149e71a4345b4b2105c17279ee2b9 -r 2c5f5e48d084b1bbfab25d663374abc6f5dc68f8 TinyIoC/TinyMessenger.cs --- a/TinyIoC/TinyMessenger.cs Sat Mar 13 11:21:23 2010 +0000 +++ b/TinyIoC/TinyMessenger.cs Sat Mar 13 12:33:13 2010 +0000 @@ -88,9 +88,44 @@ /// /// Represents an active subscription to a message /// - public sealed class TinyMessageSubscription + public sealed class TinyMessageSubscriptionToken { } + + /// + /// Represents a message subscription + /// + public interface ITinyMessageSubscription + { + /// + /// Token returned to the subscribed to reference this subscription + /// + TinyMessageSubscriptionToken SubscriptionToken { get; } + + /// + /// Whether delivery should be attempted. + /// + /// Message that may potentially be delivered. + /// True - ok to send, False - should not attempt to send + bool ShouldAttemptDelivery(ITinyMessage message); + + /// + /// Deliver the message + /// + /// Message to deliver + void Deliver(ITinyMessage message); + } + + /// + /// Message proxy definition. + /// + /// A message proxy can be used to intercept/alter messages and/or + /// marshall delivery actions onto a particular thread. + /// + public interface ITinyMessageProxy + { + void Deliver(ITinyMessage message, ITinyMessageSubscription subscription); + } #endregion #region Exceptions @@ -130,7 +165,20 @@ /// Type of message /// Action to invoke when message is delivered /// TinyMessageSubscription used to unsubscribing - TinyMessageSubscription Subscribe(Action deliveryAction) where TMessage : class, ITinyMessage; + TinyMessageSubscriptionToken Subscribe(Action deliveryAction) where TMessage : class, ITinyMessage; + + /// + /// Subscribe to a message type with the given destination and delivery action. + /// Messages will be delivered via the specified proxy. + /// All references (apart from the proxy) are held with WeakReferences + /// + /// All messages of this type will be delivered. + /// + /// Type of message + /// Action to invoke when message is delivered + /// Proxy to use when delivering the messages + /// TinyMessageSubscription used to unsubscribing + TinyMessageSubscriptionToken Subscribe(Action deliveryAction, ITinyMessageProxy proxy) where TMessage : class, ITinyMessage; /// /// Subscribe to a message type with the given destination and delivery action. @@ -141,7 +189,20 @@ /// Action to invoke when message is delivered /// Use strong references to destination and deliveryAction /// TinyMessageSubscription used to unsubscribing - TinyMessageSubscription Subscribe(Action deliveryAction, bool useStrongReferences) where TMessage : class, ITinyMessage; + TinyMessageSubscriptionToken Subscribe(Action deliveryAction, bool useStrongReferences) where TMessage : class, ITinyMessage; + + /// + /// Subscribe to a message type with the given destination and delivery action. + /// Messages will be delivered via the specified proxy. + /// + /// All messages of this type will be delivered. + /// + /// Type of message + /// Action to invoke when message is delivered + /// Use strong references to destination and deliveryAction + /// Proxy to use when delivering the messages + /// TinyMessageSubscription used to unsubscribing + TinyMessageSubscriptionToken Subscribe(Action deliveryAction, bool useStrongReferences, ITinyMessageProxy proxy) where TMessage : class, ITinyMessage; /// /// Subscribe to a message type with the given destination and delivery action with the given filter. @@ -152,7 +213,20 @@ /// Type of message /// Action to invoke when message is delivered /// TinyMessageSubscription used to unsubscribing - TinyMessageSubscription Subscribe(Action deliveryAction, Func messageFilter) where TMessage : class, ITinyMessage; + TinyMessageSubscriptionToken Subscribe(Action deliveryAction, Func messageFilter) where TMessage : class, ITinyMessage; + + /// + /// Subscribe to a message type with the given destination and delivery action with the given filter. + /// Messages will be delivered via the specified proxy. + /// All references (apart from the proxy) are held with WeakReferences + /// + /// Only messages that "pass" the filter will be delivered. + /// + /// Type of message + /// Action to invoke when message is delivered + /// Proxy to use when delivering the messages + /// TinyMessageSubscription used to unsubscribing + TinyMessageSubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, ITinyMessageProxy proxy) where TMessage : class, ITinyMessage; /// /// Subscribe to a message type with the given destination and delivery action with the given filter. @@ -164,7 +238,21 @@ /// Action to invoke when message is delivered /// Use strong references to destination and deliveryAction /// TinyMessageSubscription used to unsubscribing - TinyMessageSubscription Subscribe(Action deliveryAction, Func messageFilter, bool useStrongReferences) where TMessage : class, ITinyMessage; + TinyMessageSubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, bool useStrongReferences) where TMessage : class, ITinyMessage; + + /// + /// Subscribe to a message type with the given destination and delivery action with the given filter. + /// Messages will be delivered via the specified proxy. + /// All references are held with WeakReferences + /// + /// Only messages that "pass" the filter will be delivered. + /// + /// Type of message + /// Action to invoke when message is delivered + /// Use strong references to destination and deliveryAction + /// Proxy to use when delivering the messages + /// TinyMessageSubscription used to unsubscribing + TinyMessageSubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, bool useStrongReferences, ITinyMessageProxy proxy) where TMessage : class, ITinyMessage; /// /// Unsubscribe from a particular message type. @@ -172,8 +260,8 @@ /// Does not throw an exception if the subscription is not found. /// /// Type of message - /// Destination (usually "this") that was used to subscribe initially - void Unsubscribe(TinyMessageSubscription subscription) where TMessage : class, ITinyMessage; + /// Subscription token received from Subscribe + void Unsubscribe(TinyMessageSubscriptionToken subscriptionToken) where TMessage : class, ITinyMessage; /// /// Publish a message to any subscribers @@ -191,25 +279,16 @@ public sealed class TinyMessengerHub : ITinyMessengerHub { #region Private Types and Interfaces - // Horrible fudge to use as the dictionary data type - // can't think of any other way without generic contravariance? - private interface ITinyMessageSubscription - { - TinyMessageSubscription Subscription { get; } - bool ShouldAttemptDelivery(ITinyMessage message); - void Deliver(ITinyMessage message); - } - private class WeakTinyMessageSubscription : ITinyMessageSubscription where TMessage : class, ITinyMessage { - protected TinyMessageSubscription _Subscription; + protected TinyMessageSubscriptionToken _SubscriptionToken; protected WeakReference _DeliveryAction; protected WeakReference _MessageFilter; - public TinyMessageSubscription Subscription + public TinyMessageSubscriptionToken SubscriptionToken { - get { return _Subscription; } + get { return _SubscriptionToken; } } public bool ShouldAttemptDelivery(ITinyMessage message) @@ -234,14 +313,7 @@ if (!_DeliveryAction.IsAlive) return; - try - { - ((Action)_DeliveryAction.Target).Invoke(message as TMessage); - } - catch (Exception) - { - // We don't want publish exceptions to bubble up - } + ((Action)_DeliveryAction.Target).Invoke(message as TMessage); } /// @@ -250,10 +322,10 @@ /// Destination object /// Delivery action /// Filter function - public WeakTinyMessageSubscription(TinyMessageSubscription subscription, Action deliveryAction, Func messageFilter) + public WeakTinyMessageSubscription(TinyMessageSubscriptionToken subscriptionToken, Action deliveryAction, Func messageFilter) { - if (subscription == null) - throw new ArgumentNullException("subscription"); + if (subscriptionToken == null) + throw new ArgumentNullException("subscriptionToken"); if (deliveryAction == null) throw new ArgumentNullException("deliveryAction"); @@ -261,7 +333,7 @@ if (messageFilter == null) throw new ArgumentNullException("messageFilter"); - _Subscription = subscription; + _SubscriptionToken = subscriptionToken; _DeliveryAction = new WeakReference(deliveryAction); _MessageFilter = new WeakReference(messageFilter); } @@ -270,13 +342,13 @@ private class StrongTinyMessageSubscription : ITinyMessageSubscription where TMessage : class, ITinyMessage { - protected TinyMessageSubscription _Subscription; + protected TinyMessageSubscriptionToken _SubscriptionToken; protected Action _DeliveryAction; protected Func _MessageFilter; - public TinyMessageSubscription Subscription + public TinyMessageSubscriptionToken SubscriptionToken { - get { return _Subscription; } + get { return _SubscriptionToken; } } public bool ShouldAttemptDelivery(ITinyMessage message) @@ -292,14 +364,7 @@ if (!(message is TMessage)) throw new ArgumentException("Message is not the correct type"); - try - { - _DeliveryAction.Invoke(message as TMessage); - } - catch (Exception) - { - // We don't want publish exceptions to bubble up - } + _DeliveryAction.Invoke(message as TMessage); } /// @@ -308,10 +373,10 @@ /// Destination object /// Delivery action /// Filter function - public StrongTinyMessageSubscription(TinyMessageSubscription subscription, Action deliveryAction, Func messageFilter) + public StrongTinyMessageSubscription(TinyMessageSubscriptionToken subscriptionToken, Action deliveryAction, Func messageFilter) { - if (subscription == null) - throw new ArgumentNullException("subscription"); + if (subscriptionToken == null) + throw new ArgumentNullException("subscriptionToken"); if (deliveryAction == null) throw new ArgumentNullException("deliveryAction"); @@ -319,16 +384,40 @@ if (messageFilter == null) throw new ArgumentNullException("messageFilter"); - _Subscription = subscription; + _SubscriptionToken = subscriptionToken; _DeliveryAction = deliveryAction; _MessageFilter = messageFilter; } } + + #region Default Message Proxy + Singleton + private static readonly ITinyMessageProxy _DefaultTinyMessageProxy = new DefaultPassThroughTinyMessageProxy(); + + private class DefaultPassThroughTinyMessageProxy : ITinyMessageProxy + { + public void Deliver(ITinyMessage message, ITinyMessageSubscription subscription) + { + subscription.Deliver(message); + } + } + #endregion #endregion #region Subscription dictionary + private class SubscriptionItem + { + public ITinyMessageProxy Proxy { get; private set; } + public ITinyMessageSubscription Subscription { get; private set; } + + public SubscriptionItem(ITinyMessageProxy proxy, ITinyMessageSubscription subscription) + { + Proxy = proxy; + Subscription = subscription; + } + } + private readonly object _SubscriptionsPadlock = new object(); - private readonly Dictionary> _Subscriptions = new Dictionary>(); + private readonly Dictionary> _Subscriptions = new Dictionary>(); #endregion #region Public API @@ -341,9 +430,25 @@ /// Type of message /// Action to invoke when message is delivered /// TinyMessageSubscription used to unsubscribing - public TinyMessageSubscription Subscribe(Action deliveryAction) where TMessage : class, ITinyMessage + public TinyMessageSubscriptionToken Subscribe(Action deliveryAction) where TMessage : class, ITinyMessage { - return AddSubscriptionInternal(deliveryAction, (m) => true, false); + return AddSubscriptionInternal(deliveryAction, (m) => true, false, _DefaultTinyMessageProxy); + } + + /// + /// Subscribe to a message type with the given destination and delivery action. + /// Messages will be delivered via the specified proxy. + /// All references (apart from the proxy) are held with WeakReferences + /// + /// All messages of this type will be delivered. + /// + /// Type of message + /// Action to invoke when message is delivered + /// Proxy to use when delivering the messages + /// TinyMessageSubscription used to unsubscribing + public TinyMessageSubscriptionToken Subscribe(Action deliveryAction, ITinyMessageProxy proxy) where TMessage : class, ITinyMessage + { + return AddSubscriptionInternal(deliveryAction, (m) => true, false, proxy); } /// @@ -355,9 +460,25 @@ /// Action to invoke when message is delivered /// Use strong references to destination and deliveryAction /// TinyMessageSubscription used to unsubscribing - public TinyMessageSubscription Subscribe(Action deliveryAction, bool useStrongReferences) where TMessage : class, ITinyMessage + public TinyMessageSubscriptionToken Subscribe(Action deliveryAction, bool useStrongReferences) where TMessage : class, ITinyMessage { - return AddSubscriptionInternal(deliveryAction, (m) => true, useStrongReferences); + return AddSubscriptionInternal(deliveryAction, (m) => true, useStrongReferences, _DefaultTinyMessageProxy); + } + + /// + /// Subscribe to a message type with the given destination and delivery action. + /// Messages will be delivered via the specified proxy. + /// + /// All messages of this type will be delivered. + /// + /// Type of message + /// Action to invoke when message is delivered + /// Use strong references to destination and deliveryAction + /// Proxy to use when delivering the messages + /// TinyMessageSubscription used to unsubscribing + public TinyMessageSubscriptionToken Subscribe(Action deliveryAction, bool useStrongReferences, ITinyMessageProxy proxy) where TMessage : class, ITinyMessage + { + return AddSubscriptionInternal(deliveryAction, (m) => true, useStrongReferences, proxy); } /// @@ -369,9 +490,25 @@ /// Type of message /// Action to invoke when message is delivered /// TinyMessageSubscription used to unsubscribing - public TinyMessageSubscription Subscribe(Action deliveryAction, Func messageFilter) where TMessage : class, ITinyMessage + public TinyMessageSubscriptionToken Subscribe(Action deliveryAction, Func messageFilter) where TMessage : class, ITinyMessage { - return AddSubscriptionInternal(deliveryAction, messageFilter, false); + return AddSubscriptionInternal(deliveryAction, messageFilter, false, _DefaultTinyMessageProxy); + } + + /// + /// Subscribe to a message type with the given destination and delivery action with the given filter. + /// Messages will be delivered via the specified proxy. + /// All references (apart from the proxy) are held with WeakReferences + /// + /// Only messages that "pass" the filter will be delivered. + /// + /// Type of message + /// Action to invoke when message is delivered + /// Proxy to use when delivering the messages + /// TinyMessageSubscription used to unsubscribing + public TinyMessageSubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, ITinyMessageProxy proxy) where TMessage : class, ITinyMessage + { + return AddSubscriptionInternal(deliveryAction, messageFilter, false, proxy); } /// @@ -384,9 +521,26 @@ /// Action to invoke when message is delivered /// Use strong references to destination and deliveryAction /// TinyMessageSubscription used to unsubscribing - public TinyMessageSubscription Subscribe(Action deliveryAction, Func messageFilter, bool useStrongReferences) where TMessage : class, ITinyMessage + public TinyMessageSubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, bool useStrongReferences) where TMessage : class, ITinyMessage { - return AddSubscriptionInternal(deliveryAction, messageFilter, useStrongReferences); + return AddSubscriptionInternal(deliveryAction, messageFilter, useStrongReferences, _DefaultTinyMessageProxy); + } + + /// + /// Subscribe to a message type with the given destination and delivery action with the given filter. + /// Messages will be delivered via the specified proxy. + /// All references are held with WeakReferences + /// + /// Only messages that "pass" the filter will be delivered. + /// + /// Type of message + /// Action to invoke when message is delivered + /// Use strong references to destination and deliveryAction + /// Proxy to use when delivering the messages + /// TinyMessageSubscription used to unsubscribing + public TinyMessageSubscriptionToken Subscribe(Action deliveryAction, Func messageFilter, bool useStrongReferences, ITinyMessageProxy proxy) where TMessage : class, ITinyMessage + { + return AddSubscriptionInternal(deliveryAction, messageFilter, useStrongReferences, proxy); } /// @@ -395,10 +549,10 @@ /// Does not throw an exception if the subscription is not found. /// /// Type of message - /// Destination (usually "this") that was used to subscribe initially - public void Unsubscribe(TinyMessageSubscription subscription) where TMessage : class, ITinyMessage + /// Subscription token received from Subscribe + public void Unsubscribe(TinyMessageSubscriptionToken subscriptionToken) where TMessage : class, ITinyMessage { - RemoveSubscriptionInternal(subscription); + RemoveSubscriptionInternal(subscriptionToken); } /// @@ -413,7 +567,7 @@ #endregion #region Internal Methods - private TinyMessageSubscription AddSubscriptionInternal(Action deliveryAction, Func messageFilter, bool strongReference) + private TinyMessageSubscriptionToken AddSubscriptionInternal(Action deliveryAction, Func messageFilter, bool strongReference, ITinyMessageProxy proxy) where TMessage : class, ITinyMessage { if (deliveryAction == null) @@ -422,41 +576,47 @@ if (messageFilter == null) throw new ArgumentNullException("messageFilter"); + if (proxy == null) + throw new ArgumentNullException("proxy"); + lock (_SubscriptionsPadlock) { - List currentSubscriptions; + List currentSubscriptions; if (!_Subscriptions.TryGetValue(typeof(TMessage), out currentSubscriptions)) { - currentSubscriptions = new List(); + currentSubscriptions = new List(); _Subscriptions[typeof(TMessage)] = currentSubscriptions; } - var subscription = new TinyMessageSubscription(); + var subscriptionToken = new TinyMessageSubscriptionToken(); + ITinyMessageSubscription subscription; if (strongReference) - currentSubscriptions.Add(new StrongTinyMessageSubscription(subscription, deliveryAction, messageFilter)); + subscription = new StrongTinyMessageSubscription(subscriptionToken, deliveryAction, messageFilter); else - currentSubscriptions.Add(new WeakTinyMessageSubscription(subscription, deliveryAction, messageFilter)); + subscription = new WeakTinyMessageSubscription(subscriptionToken, deliveryAction, messageFilter); - return subscription; + currentSubscriptions.Add(new SubscriptionItem(proxy, subscription)); + + return subscriptionToken; } } - private void RemoveSubscriptionInternal(TinyMessageSubscription subscription) + private void RemoveSubscriptionInternal(TinyMessageSubscriptionToken subscriptionToken) where TMessage : class, ITinyMessage { - if (subscription == null) - throw new ArgumentNullException("subscription"); + if (subscriptionToken == null) + throw new ArgumentNullException("subscriptionToken"); lock (_SubscriptionsPadlock) { - List currentSubscriptions; + List currentSubscriptions; if (!_Subscriptions.TryGetValue(typeof(TMessage), out currentSubscriptions)) return; var currentlySubscribed = (from sub in currentSubscriptions - where object.ReferenceEquals(sub.Subscription, subscription) + where object.ReferenceEquals(sub.Subscription.SubscriptionToken, subscriptionToken) select sub).ToList(); currentlySubscribed.ForEach(sub => currentSubscriptions.Remove(sub)); @@ -469,22 +629,30 @@ if (message == null) throw new ArgumentNullException("message"); - List currentlySubscribed; + List currentlySubscribed; lock (_SubscriptionsPadlock) { - List currentSubscriptions; + List currentSubscriptions; if (!_Subscriptions.TryGetValue(typeof(TMessage), out currentSubscriptions)) return; currentlySubscribed = (from sub in currentSubscriptions - where sub.ShouldAttemptDelivery(message) + where sub.Subscription.ShouldAttemptDelivery(message) select sub).ToList(); } - foreach (var sub in currentlySubscribed) + currentlySubscribed.ForEach(sub => { - sub.Deliver(message); - } + try + { + sub.Proxy.Deliver(message, sub.Subscription); + } + catch (Exception) + { + // Ignore any errors and carry on + // TODO - add to a list of erroring subs and remove them? + } + }); } #endregion }