Просмотр исходного кода

Merge pull request #7 from Abc-Arbitrage/SubscriptionMode

LGTM
Kévin LOVATO 11 лет назад
Родитель
Сommit
635b6ca050

+ 2 - 0
src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj

@@ -100,6 +100,8 @@
     <Compile Include="Dispatch\DispatchMessages\ForwardCommand.cs" />
     <Compile Include="Dispatch\DispatchMessages\ForwardCommandHandler.cs" />
     <Compile Include="Dispatch\DispatcherTaskSchedulerTests.cs" />
+    <Compile Include="Dispatch\DispatchMessages\ManualCommand.cs" />
+    <Compile Include="Dispatch\DispatchMessages\ManualCommandHandler.cs" />
     <Compile Include="Dispatch\MessageDispatcherTests.CustomQueues.cs" />
     <Compile Include="Dispatch\DispatchMessages\Namespace1\UseOtherQueue.cs" />
     <Compile Include="Dispatch\DispatchMessages\Namespace1\Namespace2\SyncCommandHandlerWithOtherQueueName.cs" />

+ 9 - 0
src/Abc.Zebus.Tests/Dispatch/DispatchMessages/ManualCommand.cs

@@ -0,0 +1,9 @@
+using ProtoBuf;
+
+namespace Abc.Zebus.Tests.Dispatch.DispatchMessages
+{
+    [ProtoContract]
+    public class ManualCommand : ICommand
+    {
+    }
+}

+ 7 - 0
src/Abc.Zebus.Tests/Dispatch/DispatchMessages/ManualCommandHandler.cs

@@ -0,0 +1,7 @@
+namespace Abc.Zebus.Tests.Dispatch.DispatchMessages
+{
+    public class ManualCommandHandler
+    {
+         
+    }
+}

+ 42 - 2
src/Abc.Zebus.Tests/Scan/SyncMessageHandlerInvokerLoaderTests.cs

@@ -1,6 +1,7 @@
 using System;
 using System.Linq;
 using Abc.Zebus.Dispatch;
+using Abc.Zebus.Routing;
 using Abc.Zebus.Scan;
 using Abc.Zebus.Testing.Extensions;
 using Abc.Zebus.Util;
@@ -16,9 +17,27 @@ namespace Abc.Zebus.Tests.Scan
         public void should_load_queue_name()
         {
             var invokerLoader = new SyncMessageHandlerInvokerLoader(new Container());
-            var invokers = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType<FakeHandlerWithQueueName1>()).ToList();
+            var invoker = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType<FakeHandlerWithQueueName1>()).ExpectedSingle();
 
-            invokers[0].DispatchQueueName.ShouldEqual("DispatchQueue1");
+            invoker.DispatchQueueName.ShouldEqual("DispatchQueue1");
+        }
+
+        [Test]
+        public void should_switch_to_manual_subscription_mode_when_specified()
+        {
+            var invokerLoader = new SyncMessageHandlerInvokerLoader(new Container());
+            var invoker = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType<FakeHandlerWithManualSubscriptionMode>()).ExpectedSingle();
+
+            invoker.ShouldBeSubscribedOnStartup.ShouldBeFalse();
+        }
+
+        [Test]
+        public void should_switch_to_auto_subscription_mode_when_specified()
+        {
+            var invokerLoader = new SyncMessageHandlerInvokerLoader(new Container());
+            var invoker = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType<FakeRoutableHandlerWithAutoSubscriptionMode>()).ExpectedSingle();
+
+            invoker.ShouldBeSubscribedOnStartup.ShouldBeTrue();
         }
 
         [Test]
@@ -43,6 +62,11 @@ namespace Abc.Zebus.Tests.Scan
         {
         }
 
+        [Routable]
+        public class FakeRoutableMessage : IMessage
+        {
+        }
+
         public class FakeHandler : IMessageHandler<FakeMessage>, IMessageHandler<FakeMessage2>
         {
             public void Handle(FakeMessage message)
@@ -71,5 +95,21 @@ namespace Abc.Zebus.Tests.Scan
             {
             }
         }
+
+        [SubscriptionMode(SubscriptionMode.Manual)]
+        public class FakeHandlerWithManualSubscriptionMode : IMessageHandler<FakeMessage>
+        {
+            public void Handle(FakeMessage message)
+            {
+            }
+        }
+
+        [SubscriptionMode(SubscriptionMode.Auto)]
+        public class FakeRoutableHandlerWithAutoSubscriptionMode : IMessageHandler<FakeRoutableMessage>
+        {
+            public void Handle(FakeRoutableMessage message)
+            {
+            }
+        }
     }
 }

+ 2 - 0
src/Abc.Zebus/Abc.Zebus.csproj

@@ -178,6 +178,8 @@
     <Compile Include="Routing\Routable.cs" />
     <Compile Include="Routing\RoutingPositionAttribute.cs" />
     <Compile Include="EventSourcing\SerializationIdAttribute.cs" />
+    <Compile Include="SubscriptionMode.cs" />
+    <Compile Include="SubscriptionModeAttribute.cs" />
     <Compile Include="TransientAttribute.cs" />
     <Compile Include="Subscription.cs" />
     <Compile Include="Serialization\IMessageSerializer.cs" />

+ 5 - 2
src/Abc.Zebus/Dispatch/MessageHandlerInvoker.cs

@@ -44,9 +44,12 @@ namespace Abc.Zebus.Dispatch
             return new Task(() => InvokeMessageHandler(invocation), TaskCreationOptions.HideScheduler);
         }
 
-        protected internal static bool MessageShouldBeSubscribedOnStartup(Type messageType, bool isNoScanHandler = false)
+        protected internal static bool MessageShouldBeSubscribedOnStartup(Type messageType, SubscriptionMode? subscriptionMode = null)
         {
-            return !isNoScanHandler && !Attribute.IsDefined(messageType, typeof(Routable));
+            if (subscriptionMode != null)
+                return subscriptionMode == SubscriptionMode.Auto;
+
+            return !Attribute.IsDefined(messageType, typeof(Routable));
         }
 
         protected object CreateHandler(IContainer container, MessageContext messageContext)

+ 18 - 7
src/Abc.Zebus/Scan/MessageHandlerInvokerLoader.cs

@@ -24,14 +24,13 @@ namespace Abc.Zebus.Scan
 
         public IEnumerable<IMessageHandlerInvoker> LoadMessageHandlerInvokers(TypeSource typeSource)
         {
-            foreach (var type in typeSource.GetTypes())
+            foreach (var handlerType in typeSource.GetTypes())
             {
-                if (!type.IsClass || type.IsAbstract || !type.IsVisible || !_handlerType.IsAssignableFrom(type))
+                if (!handlerType.IsClass || handlerType.IsAbstract || !handlerType.IsVisible || !_handlerType.IsAssignableFrom(handlerType))
                     continue;
 
-                var isNoScanHandler = Attribute.IsDefined(type, typeof(NoScanAttribute));
-
-                var interfaces = type.GetInterfaces();
+                var subscriptionMode = GetExplicitSubscriptionMode(handlerType);
+                var interfaces = handlerType.GetInterfaces();
 
                 var excludedMessageTypes = interfaces.Where(IsExtendedMessageHandlerInterface)
                                                      .Select(handleInterface => handleInterface.GetGenericArguments()[0])
@@ -44,13 +43,25 @@ namespace Abc.Zebus.Scan
                     if (excludedMessageTypes.Contains(messageType))
                         continue;
 
-                    var shouldBeSubscribedOnStartup = MessageHandlerInvoker.MessageShouldBeSubscribedOnStartup(messageType, isNoScanHandler);
-                    var invoker = BuildMessageHandlerInvoker(type, messageType, shouldBeSubscribedOnStartup);
+                    var shouldBeSubscribedOnStartup = MessageHandlerInvoker.MessageShouldBeSubscribedOnStartup(messageType, subscriptionMode);
+                    var invoker = BuildMessageHandlerInvoker(handlerType, messageType, shouldBeSubscribedOnStartup);
                     yield return invoker;
                 }
             }
         }
 
+        private SubscriptionMode? GetExplicitSubscriptionMode(Type handlerType)
+        {
+            var subscriptionModeAttribute = (SubscriptionModeAttribute)Attribute.GetCustomAttribute(handlerType, typeof(SubscriptionModeAttribute));
+            if (subscriptionModeAttribute != null)
+                return subscriptionModeAttribute.SubscriptionMode;
+
+            var isNoScanHandler = Attribute.IsDefined(handlerType, typeof(NoScanAttribute));
+            if (isNoScanHandler)
+                return SubscriptionMode.Manual;
+
+            return null;
+        }
 
         protected abstract IMessageHandlerInvoker BuildMessageHandlerInvoker(Type handlerType, Type messageType, bool shouldBeSubscribedOnStartup);
 

+ 16 - 0
src/Abc.Zebus/SubscriptionMode.cs

@@ -0,0 +1,16 @@
+namespace Abc.Zebus
+{
+    public enum SubscriptionMode
+    {
+        /// <summary>
+        /// A subscription for the handler message type will be automatically performed on startup.
+        /// This is the default mode for non-routable messages.
+        /// </summary>
+        Auto,
+        /// <summary>
+        /// The subscription for the handler message type must be manually performed with <code>IBus.Subscribe</code>.
+        /// This is the default mode for routable messages.
+        /// </summary>
+        Manual,
+    }
+}

+ 17 - 0
src/Abc.Zebus/SubscriptionModeAttribute.cs

@@ -0,0 +1,17 @@
+using System;
+
+namespace Abc.Zebus
+{
+    /// <summary>
+    /// Specifies the subscription mode of the target message handler.
+    /// </summary>
+    public class SubscriptionModeAttribute : Attribute
+    {
+        public SubscriptionModeAttribute(SubscriptionMode subscriptionMode)
+        {
+            SubscriptionMode = subscriptionMode;
+        }
+
+        public SubscriptionMode SubscriptionMode { get; private set; }
+    }
+}