From 5749d89b8848cfd349173714ec30606395a92a3f Mon Sep 17 00:00:00 2001 From: Tom Cabanski Date: Sun, 2 Oct 2011 12:54:26 -0500 Subject: [PATCH] Message handler get registered with the container. If the handler class is decorated with [SingletonMessageHandler], the handler is registered as a singleton. Otherwise, the message handler is registered per dependency. Handler is instantiated from the container to handle the message so the handler will get dependencies injected automatically. The IsReusable attribute is not needed (or checked) on message handlers. Message handlers no longer require a default constructor. --- ...tExtensions.Azure.ServiceBus.6.0.ReSharper | 324 ++++++++++++++++++ readme.txt | 7 - .../AzureBus.cs | 33 +- .../AzureBusReceiver.cs | 10 +- .../IMessageHandler.cs | 11 +- .../ProjectExtensions.Azure.ServiceBus.csproj | 1 + .../ServiceBusEnpointData.cs | 16 +- .../SingletonMessageHandlerAttribute.cs | 9 + .../AnotherTestMessageSubscriber.cs | 6 - .../TestMessageSubscriber.cs | 10 +- 10 files changed, 367 insertions(+), 60 deletions(-) create mode 100644 ProjectExtensions.Azure.ServiceBus.6.0.ReSharper create mode 100644 src/ProjectExtensions.Azure.ServiceBus/SingletonMessageHandlerAttribute.cs diff --git a/ProjectExtensions.Azure.ServiceBus.6.0.ReSharper b/ProjectExtensions.Azure.ServiceBus.6.0.ReSharper new file mode 100644 index 0000000..59b10bd --- /dev/null +++ b/ProjectExtensions.Azure.ServiceBus.6.0.ReSharper @@ -0,0 +1,324 @@ + + + + + SOLUTION + + + + + + + False + END_OF_LINE + END_OF_LINE + TOGETHER_SAME_LINE + False + False + ALWAYS_ADD + False + False + END_OF_LINE + END_OF_LINE + + public + protected + internal + private + new + abstract + virtual + override + sealed + static + readonly + extern + unsafe + volatile + + END_OF_LINE + False + False + False + False + END_OF_LINE + 200 + + + + $object$_On$event$ + $event$Handler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + + + + + + + + $object$_On$event$ + $event$Handler + + + + + + + + + + + + + + $object$_On$event$ + $event$Handler + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/readme.txt b/readme.txt index f8a54db..c15a6ef 100644 --- a/readme.txt +++ b/readme.txt @@ -36,13 +36,6 @@ public class TestMessageSubscriber : IHandleMessages { public void Handle(TestMessage message, IDictionary metadata) { logger.Log(LogLevel.Info, "Message received: {0} {1}", message.Value, message.MessageId); } - - public bool IsReusable { - get { - return false; - } - } - } diff --git a/src/ProjectExtensions.Azure.ServiceBus/AzureBus.cs b/src/ProjectExtensions.Azure.ServiceBus/AzureBus.cs index 20340f7..81a35c5 100644 --- a/src/ProjectExtensions.Azure.ServiceBus/AzureBus.cs +++ b/src/ProjectExtensions.Azure.ServiceBus/AzureBus.cs @@ -141,34 +141,41 @@ public class AzureBus : IBus { subscribedTypes.Add(type); - ConstructorInfo ctor = type.GetConstructors().Where(item => item.GetParameters().Count() == 0).First(); - var activator = ReflectionHelper.GetActivator(ctor); - - //non generic types only for now. - var instance = activator(new object[] { null }); - var castProperty = instance.GetType().GetProperty("IsReusable"); - var canReuse = (bool)castProperty.GetGetMethod().Invoke(instance, null); + var builder = new ContainerBuilder(); //for each interface we find, we need to register it with the bus. foreach (var foundInterface in interfaces) { - var implementedType = foundInterface.GetGenericArguments()[0]; + var implementedMessageType = foundInterface.GetGenericArguments()[0]; //due to the limits of 50 chars we will take the name and a MD5 for the name. - var hashName = implementedType.FullName + "|" + type.FullName; + var hashName = implementedMessageType.FullName + "|" + type.FullName; var hash = Helpers.CalculateMD5(hashName); var fullName = (IsCompetingHandler(foundInterface) ? "C_" : config.ServiceBusApplicationId + "_") + hash; var info = new ServiceBusEnpointData() { DeclaredType = type, - IsReusable = canReuse, - MessageType = implementedType, - StaticInstance = instance, - SubscriptionName = fullName + MessageType = implementedMessageType, + SubscriptionName = fullName, + ServiceType = foundInterface, + IsReusable = (type.GetCustomAttributes(typeof(SingletonMessageHandlerAttribute), false).Count() > 0) }; + + if (!BusConfiguration.Container.IsRegistered(type)) { + if (info.IsReusable) { + builder.RegisterType(type).SingleInstance(); + } + else { + builder.RegisterType(type).InstancePerDependency(); + } + } + + callback(info); } + + builder.Update(BusConfiguration.Container); } } } diff --git a/src/ProjectExtensions.Azure.ServiceBus/AzureBusReceiver.cs b/src/ProjectExtensions.Azure.ServiceBus/AzureBusReceiver.cs index f7249c9..dc2400e 100644 --- a/src/ProjectExtensions.Azure.ServiceBus/AzureBusReceiver.cs +++ b/src/ProjectExtensions.Azure.ServiceBus/AzureBusReceiver.cs @@ -171,14 +171,8 @@ public AzureBusReceiver(BusConfiguration configuration) logger.Log(LogLevel.Info, "ProcessMessage invoke callback message start message={0} Thread={1} MessageId={2}", state.Data.EndPointData.SubscriptionName, Thread.CurrentThread.ManagedThreadId, state.Message.MessageId); - if (state.Data.EndPointData.IsReusable && state.Data.EndPointData.StaticInstance != null) { - state.MethodInfo.Invoke(state.Data.EndPointData.StaticInstance, new object[] { receivedMessage, values }); - } - else { - var obj = Activator.CreateInstance(state.Data.EndPointData.DeclaredType); - state.MethodInfo.Invoke(obj, new object[] { receivedMessage, values }); - } - + var handler = BusConfiguration.Container.Resolve(state.Data.EndPointData.DeclaredType); + state.MethodInfo.Invoke(handler, new object[] {receivedMessage, values}); logger.Log(LogLevel.Info, "ProcessMessage invoke callback message end message={0} Thread={1} MessageId={2}", state.Data.EndPointData.SubscriptionName, Thread.CurrentThread.ManagedThreadId, state.Message.MessageId); } state.Message.Complete(); diff --git a/src/ProjectExtensions.Azure.ServiceBus/IMessageHandler.cs b/src/ProjectExtensions.Azure.ServiceBus/IMessageHandler.cs index cc1e304..d0ac5ca 100644 --- a/src/ProjectExtensions.Azure.ServiceBus/IMessageHandler.cs +++ b/src/ProjectExtensions.Azure.ServiceBus/IMessageHandler.cs @@ -9,15 +9,8 @@ namespace ProjectExtensions.Azure.ServiceBus { /// Basic message Handler /// /// The type of message to be handled. + /// A new handler will be instantiated for each message unless you decorate your handler class with [SingletonMessageHandler] public interface IMessageHandler { - - /// - /// Is your handler thread safe. - /// - bool IsReusable { - get; - } - /// /// Process a Message with the given signature. /// @@ -34,6 +27,7 @@ public interface IMessageHandler { /// Interface that needs to be implemented if you wish to register a subscription. /// /// + /// A new handler will be instantiated for each message unless you decorate your handler class with [SingletonMessageHandler] public interface IHandleMessages : IMessageHandler { } @@ -43,6 +37,7 @@ public interface IHandleMessages : IMessageHandler { /// /// This implementation will allow the Topic to scale out, allowing multiple subscibers to handle the messages sent. /// + /// A new handler will be instantiated for each message unless you decorate your handler class with [SingletonMessageHandler] public interface IHandleCompetingMessages : IMessageHandler { } diff --git a/src/ProjectExtensions.Azure.ServiceBus/ProjectExtensions.Azure.ServiceBus.csproj b/src/ProjectExtensions.Azure.ServiceBus/ProjectExtensions.Azure.ServiceBus.csproj index adcd787..9263f58 100644 --- a/src/ProjectExtensions.Azure.ServiceBus/ProjectExtensions.Azure.ServiceBus.csproj +++ b/src/ProjectExtensions.Azure.ServiceBus/ProjectExtensions.Azure.ServiceBus.csproj @@ -85,6 +85,7 @@ + diff --git a/src/ProjectExtensions.Azure.ServiceBus/ServiceBusEnpointData.cs b/src/ProjectExtensions.Azure.ServiceBus/ServiceBusEnpointData.cs index 1af25b2..099f1d4 100644 --- a/src/ProjectExtensions.Azure.ServiceBus/ServiceBusEnpointData.cs +++ b/src/ProjectExtensions.Azure.ServiceBus/ServiceBusEnpointData.cs @@ -15,6 +15,11 @@ class ServiceBusEnpointData { set; } + public Type ServiceType { + get; + set; + } + public string SubscriptionName { get; set; @@ -34,15 +39,6 @@ class ServiceBusEnpointData { public Type MessageType { get; set; - } - - /// - /// If the Item is IsReusable, this value will be set. - /// - public object StaticInstance { - get; - set; - } - + } } } diff --git a/src/ProjectExtensions.Azure.ServiceBus/SingletonMessageHandlerAttribute.cs b/src/ProjectExtensions.Azure.ServiceBus/SingletonMessageHandlerAttribute.cs new file mode 100644 index 0000000..b478289 --- /dev/null +++ b/src/ProjectExtensions.Azure.ServiceBus/SingletonMessageHandlerAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace ProjectExtensions.Azure.ServiceBus { + /// + /// Marks message handler as a singleton. + /// + [AttributeUsage(AttributeTargets.Class)] + public class SingletonMessageHandlerAttribute : Attribute {} +} \ No newline at end of file diff --git a/src/Samples/PubSubUsingConfiguration/AnotherTestMessageSubscriber.cs b/src/Samples/PubSubUsingConfiguration/AnotherTestMessageSubscriber.cs index 00dfeba..ac4edbb 100644 --- a/src/Samples/PubSubUsingConfiguration/AnotherTestMessageSubscriber.cs +++ b/src/Samples/PubSubUsingConfiguration/AnotherTestMessageSubscriber.cs @@ -11,12 +11,6 @@ public class AnotherTestMessageSubscriber : IHandleCompetingMessages message, IDictionary metadata) { logger.Log(LogLevel.Info, "Message received: {0} {1}", message.Message.Value, message.Message.MessageId); } diff --git a/src/Samples/PubSubUsingConfiguration/TestMessageSubscriber.cs b/src/Samples/PubSubUsingConfiguration/TestMessageSubscriber.cs index c0ea16a..fd3dafb 100644 --- a/src/Samples/PubSubUsingConfiguration/TestMessageSubscriber.cs +++ b/src/Samples/PubSubUsingConfiguration/TestMessageSubscriber.cs @@ -6,7 +6,8 @@ using NLog; namespace PubSubUsingConfiguration { - + + [SingletonMessageHandler] public class TestMessageSubscriber : IHandleMessages { static Logger logger = LogManager.GetCurrentClassLogger(); @@ -14,12 +15,5 @@ public class TestMessageSubscriber : IHandleMessages { public void Handle(IReceivedMessage message, IDictionary metadata) { logger.Log(LogLevel.Info, "Message received: {0} {1}", message.Message.Value, message.Message.MessageId); } - - public bool IsReusable { - get { - return false; - } - } - } }