├── .github └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── AdditionalHandlerAssembly ├── AdditionalHandlerAssembly.csproj └── ControllerChangeMessageHandler.cs ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── MessageHandlers ├── EventAggregator.cs ├── FirstHandler.cs ├── MessageHandlers.csproj └── SecondHandler.cs ├── README.md ├── Rebus.Autofac.Tests ├── AutofacActivationContext.cs ├── AutofacContainerTests.cs ├── AutofacRealContainerTests.cs ├── Bugs │ ├── CanGetMessageHandlerWhenDoingSecondLevelRetries.cs │ ├── DoesNotTryToHandleMessagesBeforeTheBusIsProperlyStarted.cs │ ├── RegistersHandlerAsImplementationOfIFailedForDerivedMessagesToo.cs │ ├── RegistersHandlerAsImplementationOfIFailedToo.cs │ └── ReproduceDoubleDispatchIssue.cs ├── CheckNewApi.cs ├── CheckResolutionPerformance.cs ├── Rebus.Autofac.Tests.csproj ├── TestAutofacAssumptions.cs └── TestRegistrationApi.cs ├── Rebus.Autofac.sln ├── Rebus.Autofac ├── Autofac │ └── AutofacHandlerActivator.cs ├── Config │ ├── ContainerBuilderExtensions.cs │ └── ContainerExtensions.cs ├── Internals │ ├── InternalsVisibleTo.cs │ └── TypeExtensions.cs └── Rebus.Autofac.csproj ├── appveyor.yml ├── artwork └── little_rebusbus2_copy-500x500.png ├── scripts ├── build.cmd ├── push.cmd └── release.cmd └── tools └── NuGet └── nuget.exe /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | --- 2 | Rebus is [MIT-licensed](https://opensource.org/licenses/MIT). The code submitted in this pull request needs to carry the MIT license too. By leaving this text in, __I hereby acknowledge that the code submitted in the pull request has the MIT license and can be merged with the Rebus codebase__. 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | bin 3 | deploy 4 | deploy/* 5 | _ReSharper.* 6 | *.csproj.user 7 | *.resharper.user 8 | *.ReSharper.user 9 | *.teamcity.user 10 | *.TeamCity.user 11 | *.resharper 12 | *.DotSettings.user 13 | *.dotsettings.user 14 | *.ncrunchproject 15 | *.ncrunchsolution 16 | *.suo 17 | *.cache 18 | ~$* 19 | .vs 20 | .vs/* 21 | _NCrunch_* 22 | *.user 23 | *.backup 24 | 25 | # MS Guideline 26 | **/packages/* 27 | !**/packages/build/ 28 | AssemblyInfo_Patch.cs 29 | /.idea/ 30 | -------------------------------------------------------------------------------- /AdditionalHandlerAssembly/AdditionalHandlerAssembly.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AdditionalHandlerAssembly/ControllerChangeMessageHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Threading.Tasks; 4 | using Rebus.Handlers; 5 | #pragma warning disable 1998 6 | 7 | namespace AdditionalHandlerAssembly 8 | { 9 | public class ControllerChangeMessageHandler : IHandleMessages 10 | { 11 | readonly ConcurrentQueue _handledMessages; 12 | 13 | public ControllerChangeMessageHandler(ConcurrentQueue handledMessages) => _handledMessages = handledMessages ?? throw new ArgumentNullException(nameof(handledMessages)); 14 | 15 | public async Task Handle(ControllerChangeMessage message) => _handledMessages.Enqueue(message); 16 | } 17 | 18 | public class ControllerChangeMessage { } 19 | } 20 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 2.0.0-a1 4 | * Update Autofac dependency to 4.1.0 5 | 6 | ## 2.0.0-a2 7 | * Test build 8 | 9 | ## 2.0.0-b01 10 | * Test release 11 | 12 | ## 2.0.0 13 | * Release 2.0.0 14 | 15 | ## 3.0.0 16 | * Update to Rebus 3 17 | 18 | ## 4.0.0 19 | * Update to Rebus 4 20 | * Add .NET Core support (netstandard1.6) 21 | * Fix csproj - thanks [robvanpamel] 22 | * Update Autofac dep to 4.5.0 23 | * Update contracts dep - thanks [trevorreeves] 24 | 25 | ## 5.0.0 26 | * Change API to work better with the Autofac container builder - no more `.Update` :) 27 | 28 | ## 5.1.0 29 | * Additional `RegisterRebus` overload that passes `IComponentContext` to the configuration method 30 | 31 | ## 5.2.0 32 | * Add Rebus handler registration extensions on `ContainerBuilder` and improve resolution performance 33 | 34 | ## 6.0.0 35 | * Move polymorphic handler resolution resposiblity to the container. If contravariant lookup is wanted, one must register `ContravariantRegistrationSource` on the `ContainerBuilder` 36 | * Update to Rebus 5 and Autofac 5 37 | * Fix dispatch of `IFailed` when 2nd level retry is enabled - thanks [oliverhanappi] 38 | * Fix subtle issues and make implementation that fixes dispatch of `IFailed` more elegant - thanks [oliverhanappi] 39 | * Registration helpers should only register handlers under their implemented handler interfaces 40 | * Fix resolution-during-startup race condition bug - thanks [leomenca] 41 | * Fix bug that would erronously dispatch 2nd level retries twice 42 | 43 | ## 7.0.0 44 | * Update to Rebus 6 45 | 46 | ## 7.1.0 47 | * Remove CLS compliance attribute accidentally left over from the past 48 | 49 | ## 7.2.0 50 | * Additional registration overloads - thanks [kendallb] 51 | 52 | ## 7.3.0 53 | * Move multiple registrations check to the builder's registration callback, because it doesn't interfere with the container's `IBus` registration. This way, `IBus` can be overridden/decorated if desired. The check can also be disabled alltogether by passing `disableMultipleRegistrationsCheck: true` to the `RegisterRebus` method. 54 | 55 | ## 8.0.0 56 | * Rename `startBus` to `startAutomatically` to be consistent with other modern containers 57 | * Add container extension method `container.StartBus()` to make starting the bus more convenient 58 | 59 | ## 9.0.0 60 | * Update to Rebus 8 61 | * Update to Autofac 7.1.0 62 | 63 | [kendallb]: https://github.com/kendallb 64 | [leomenca]: https://github.com/leomenca 65 | [oliverhanappi]: https://github.com/oliverhanappi 66 | [robvanpamel]: https://github.com/robvanpamel 67 | [trevorreeves]: https://github.com/trevorreeves 68 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributions are most welcome! :) 2 | 3 | I do prefer it if we communicate a little bit before you send PRs, though. 4 | This is because _I value your time_, and it would be a shame if you spent time 5 | working on something that could be made better in another way, or wasn't 6 | actually needed because what you wanted to achieve could be done better in 7 | another way, etc. 8 | 9 | ## "Beginners" 10 | 11 | Contributions are ALSO very welcome if you consider yourself a beginner 12 | at open source. Everyone has to start somewhere, right? 13 | 14 | Here's how you would ideally do it if you were to contribute to Rebus: 15 | 16 | * Pick an [issue](https://github.com/rebus-org/Rebus/issues) you're interested in doing, 17 | or dream up something yourself that you feel is missing. 18 | * If you talk to me first (either via comments on the issue or by email), I 19 | will guarantee that your contribution is accepted. 20 | * Send me a "pull request" (which is how you make contributions on GitHub) 21 | 22 | ### Here's how you create a pull request/PR 23 | 24 | * Fork Rebus ([Fork A Repo @ GitHub docs](https://help.github.com/articles/fork-a-repo/)) 25 | * Clone your fork ([Cloning A Repository @ GitHub docs](https://help.github.com/articles/cloning-a-repository/)) 26 | * Make changes to your local copy (e.g. `git commit -am"bam!!!11"` - check [this](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository) out for more info) 27 | * Push your local changes to your fork ([Pushing To A Remote @ GitHub docs](https://help.github.com/articles/pushing-to-a-remote/)) 28 | * Send me a pull request ([Using Pull Requests @ GitHub docs](https://help.github.com/articles/using-pull-requests/)) 29 | 30 | When you do this, your changes become visible to me. I can then review it, and we can discuss 31 | each line of code if necessary. 32 | 33 | If you push additional changes to your fork during this process, 34 | the changes become immediately available in the pull request. 35 | 36 | When all is good, I accept your PR by merging it, and then you're (even more) awesome! 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Rebus is licensed under [The MIT License (MIT)](http://opensource.org/licenses/MIT) 2 | 3 | # The MIT License (MIT) 4 | 5 | Copyright (c) 2012-2016 Mogens Heller Grabe 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | 25 | ------- 26 | 27 | This license was chosen with the intention of making it easy for everyone to use Rebus. If the license has the opposite effect for your specific usage/organization/whatever, please contact me and we'll see if we can work something out. -------------------------------------------------------------------------------- /MessageHandlers/EventAggregator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace MessageHandlers 7 | { 8 | public class EventAggregator : IEnumerable 9 | { 10 | readonly ConcurrentQueue _events = new ConcurrentQueue(); 11 | 12 | public void Register(string e) => _events.Enqueue(e); 13 | 14 | public IEnumerator GetEnumerator() => _events.ToList().GetEnumerator(); 15 | 16 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /MessageHandlers/FirstHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Rebus.Handlers; 3 | #pragma warning disable 1998 4 | 5 | namespace MessageHandlers 6 | { 7 | public class FirstHandler : IHandleMessages 8 | { 9 | readonly EventAggregator _eventAggregator; 10 | 11 | public FirstHandler(EventAggregator eventAggregator) => _eventAggregator = eventAggregator; 12 | 13 | public async Task Handle(string message) => _eventAggregator.Register($"FirstHandler handling {message}"); 14 | } 15 | } -------------------------------------------------------------------------------- /MessageHandlers/MessageHandlers.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netstandard2.0 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /MessageHandlers/SecondHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Rebus.Handlers; 3 | #pragma warning disable 1998 4 | 5 | namespace MessageHandlers 6 | { 7 | public class SecondHandler : IHandleMessages 8 | { 9 | readonly EventAggregator _eventAggregator; 10 | 11 | public SecondHandler(EventAggregator eventAggregator) => _eventAggregator = eventAggregator; 12 | 13 | public async Task Handle(string message) => _eventAggregator.Register($"SecondHandler handling {message}"); 14 | } 15 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rebus.Autofac 2 | 3 | [![install from nuget](https://img.shields.io/nuget/v/Rebus.Autofac.svg?style=flat-square)](https://www.nuget.org/packages/Rebus.Autofac) 4 | 5 | Provides an Autofac container adapter for [Rebus](https://github.com/rebus-org/Rebus). 6 | 7 | ![](https://raw.githubusercontent.com/rebus-org/Rebus/master/artwork/little_rebusbus2_copy-200x200.png) 8 | 9 | --- 10 | 11 | Use the Autofac container adapter like this: 12 | 13 | ```csharp 14 | var builder = new ContainerBuilder(); 15 | 16 | builder.RegisterRebus((configurer, context) => configurer 17 | .Logging(l => l.Serilog()) 18 | .Transport(t => t.UseRabbitMq(...)) 19 | .Options(o => { 20 | o.SetNumberOfWorkers(2); 21 | o.SetMaxParallelism(30); 22 | })); 23 | 24 | // the bus is registered now, but it has not been started.... make all your other registrations, and then: 25 | var container = builder.Build(); //< start the bus 26 | 27 | 28 | // now your application is running 29 | 30 | 31 | // ALWAYS do this when your application shuts down: 32 | container.Dispose(); 33 | ``` 34 | 35 | It will automatically register the following services in Autofac: 36 | 37 | * `IBus` – this is the bus singleton 38 | * `IBusStarter` – this is the bus starter you can use to start it manually 39 | * `IMessageContext` – this is the current message context – can be injected into Rebus message handlers and everything resolved at the time of receiving a new message 40 | * `ISyncBus` – this is the synchronous bus instance – can be used in places, where a `Task`-based asynchronous API is not desired, e.g. from deep within ASP.NET or WPF applications, which would deadlock if you went `.Wait()` on a `Task` 41 | 42 | Not that if you wish to regiser the bus and not start it automatically, you can stil register the number of workers but have it not start anything until you are ready for the bus to be started. This is usefu if you wish to separate the processing of messages from the sending of messages (separate tasks, services etc). You would do it like this: 43 | 44 | ```csharp 45 | var builder = new ContainerBuilder(); 46 | 47 | builder.RegisterRebus((configurer, context) => configurer 48 | .Logging(l => l.Serilog()) 49 | .Transport(t => t.UseRabbitMq(...)) 50 | .Options(o => { 51 | o.SetNumberOfWorkers(2); 52 | o.SetMaxParallelism(30); 53 | }), 54 | false); // <--- here we tell it not to start the bus 55 | 56 | // the bus is registered now, but it has not been started.... make all your other registrations, and then: 57 | var container = builder.Build(); 58 | var busStarter = container.Resolve(); 59 | busStarter.Start(); //< start the bus 60 | 61 | 62 | // now your application is running 63 | 64 | 65 | // ALWAYS do this when your application shuts down: 66 | container.Dispose(); 67 | ``` 68 | -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/AutofacActivationContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Autofac; 5 | using Rebus.Activation; 6 | using Rebus.Bus; 7 | using Rebus.Config; 8 | using Rebus.Handlers; 9 | using Rebus.Tests.Contracts.Activation; 10 | // ReSharper disable ArgumentsStyleLiteral 11 | 12 | namespace Rebus.Autofac.Tests; 13 | 14 | public class AutofacActivationContext : IActivationContext 15 | { 16 | public IHandlerActivator CreateActivator(Action configureHandlers, out IActivatedContainer container) 17 | { 18 | var builder = new ContainerBuilder(); 19 | configureHandlers(new HandlerRegistry(builder)); 20 | 21 | var containerAdapter = new AutofacHandlerActivator(builder, (conf, con) => { }, startBus: false, enablePolymorphicDispatch: true, multipleRegistrationsCheckEnabled: true); 22 | 23 | var autofacContainer = builder.Build(); 24 | container = new ActivatedContainer(autofacContainer); 25 | 26 | return containerAdapter; 27 | } 28 | 29 | public IBus CreateBus(Action configureHandlers, Func configureBus, out IActivatedContainer container) 30 | { 31 | var containerBuilder = new ContainerBuilder(); 32 | configureHandlers(new HandlerRegistry(containerBuilder)); 33 | 34 | new AutofacHandlerActivator(containerBuilder, (conf, con) => configureBus(conf), startBus: true, enablePolymorphicDispatch: true, multipleRegistrationsCheckEnabled: true); 35 | 36 | var autofacContainer = containerBuilder.Build(); 37 | container = new ActivatedContainer(autofacContainer); 38 | 39 | return container.ResolveBus(); 40 | } 41 | 42 | class HandlerRegistry : IHandlerRegistry 43 | { 44 | readonly ContainerBuilder _containerBuilder; 45 | 46 | public HandlerRegistry(ContainerBuilder containerBuilder) 47 | { 48 | _containerBuilder = containerBuilder; 49 | } 50 | 51 | public IHandlerRegistry Register() where THandler : class, IHandleMessages 52 | { 53 | _containerBuilder.RegisterType() 54 | .As(GetHandlerInterfaces().ToArray()) 55 | .InstancePerDependency(); 56 | 57 | return this; 58 | } 59 | 60 | static IEnumerable GetHandlerInterfaces() where THandler : class, IHandleMessages 61 | { 62 | return typeof(THandler) 63 | .GetInterfaces() 64 | .Where(i => HasGenericTypeDefinition(i, typeof(IHandleMessages<>))); 65 | } 66 | 67 | static bool HasGenericTypeDefinition(Type type, Type openGenericType) 68 | { 69 | return type.IsGenericType && type.GetGenericTypeDefinition() == openGenericType; 70 | } 71 | } 72 | 73 | class ActivatedContainer : IActivatedContainer 74 | { 75 | readonly IContainer _container; 76 | 77 | public ActivatedContainer(IContainer container) 78 | { 79 | _container = container; 80 | } 81 | 82 | public void Dispose() 83 | { 84 | _container.Dispose(); 85 | } 86 | 87 | public IBus ResolveBus() 88 | { 89 | return _container.Resolve(); 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/AutofacContainerTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Rebus.Tests.Contracts.Activation; 3 | 4 | namespace Rebus.Autofac.Tests; 5 | 6 | [TestFixture] 7 | public class AutofacContainerTests : ContainerTests 8 | { 9 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/AutofacRealContainerTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using Rebus.Tests.Contracts.Activation; 3 | 4 | namespace Rebus.Autofac.Tests; 5 | 6 | [TestFixture] 7 | public class AutofacRealContainerTests : RealContainerTests 8 | { 9 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/Bugs/CanGetMessageHandlerWhenDoingSecondLevelRetries.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Threading.Tasks; 4 | using Autofac; 5 | using NUnit.Framework; 6 | using Rebus.Bus; 7 | using Rebus.Config; 8 | using Rebus.Handlers; 9 | using Rebus.Retry.Simple; 10 | using Rebus.Tests.Contracts.Extensions; 11 | using Rebus.Transport.InMem; 12 | #pragma warning disable 1998 13 | 14 | namespace Rebus.Autofac.Tests.Bugs; 15 | 16 | [TestFixture] 17 | public class CanGetMessageHandlerWhenDoingSecondLevelRetries 18 | { 19 | [Test] 20 | public async Task ItWorks() 21 | { 22 | var network = new InMemNetwork(); 23 | var builder = new ContainerBuilder(); 24 | var stuff = new ConcurrentQueue(); 25 | 26 | builder.RegisterInstance(stuff); 27 | 28 | builder.RegisterRebus(configure => 29 | configure 30 | .Logging(l => l.None()) 31 | .Transport(t => t.UseInMemoryTransport(network, "test")) 32 | .Options(o => o.RetryStrategy(secondLevelRetriesEnabled: true, maxDeliveryAttempts: 1)) 33 | ); 34 | 35 | builder.RegisterHandler(); 36 | 37 | await using var container = builder.Build(); 38 | 39 | var bus = container.Resolve(); 40 | 41 | Console.WriteLine("Sending message"); 42 | await bus.SendLocal("hej søtte!"); 43 | 44 | Console.WriteLine("Waiting for message to arrive in queue 'done'..."); 45 | await network.WaitForNextMessageFrom("done"); 46 | Console.WriteLine("Got the message!"); 47 | 48 | Assert.That(stuff.Count, Is.EqualTo(1), 49 | "Expected second level handler to have been called only once!!"); 50 | } 51 | 52 | class MyTestHandler : IHandleMessages, IHandleMessages> 53 | { 54 | readonly ConcurrentQueue _stuff; 55 | readonly IBus _bus; 56 | 57 | public MyTestHandler(ConcurrentQueue stuff, IBus bus) 58 | { 59 | _stuff = stuff ?? throw new ArgumentNullException(nameof(stuff)); 60 | _bus = bus ?? throw new ArgumentNullException(nameof(bus)); 61 | } 62 | 63 | public async Task Handle(IFailed message) 64 | { 65 | Console.WriteLine("2nd level handler running"); 66 | _stuff.Enqueue($"Handled failed message: {message.Message}"); 67 | await _bus.Advanced.Routing.Send("done", "we're done now"); 68 | } 69 | 70 | public async Task Handle(string message) 71 | { 72 | Console.WriteLine("Throwing an exception now!"); 73 | throw new NotImplementedException("OH NOES"); 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/Bugs/DoesNotTryToHandleMessagesBeforeTheBusIsProperlyStarted.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Threading.Tasks; 3 | using Autofac; 4 | using NUnit.Framework; 5 | using Rebus.Activation; 6 | using Rebus.Bus; 7 | using Rebus.Config; 8 | using Rebus.Handlers; 9 | using Rebus.Logging; 10 | using Rebus.Tests.Contracts; 11 | using Rebus.Tests.Contracts.Extensions; 12 | using Rebus.Tests.Contracts.Utilities; 13 | using Rebus.Transport.InMem; 14 | // ReSharper disable RedundantArgumentDefaultValue 15 | // ReSharper disable ClassNeverInstantiated.Local 16 | // ReSharper disable ArgumentsStyleLiteral 17 | #pragma warning disable 1998 18 | 19 | namespace Rebus.Autofac.Tests.Bugs; 20 | 21 | [TestFixture] 22 | public class DoesNotTryToHandleMessagesBeforeTheBusIsProperlyStarted : FixtureBase 23 | { 24 | [Test] 25 | [Repeat(10)] 26 | public async Task ItWorks() 27 | { 28 | const string queueName = "testappqueue"; 29 | const int numberOfMessages = 10; 30 | 31 | var network = new InMemNetwork(); 32 | var listLoggerFactory = new ListLoggerFactory(detailed: true); 33 | var sharedCounter = new SharedCounter(numberOfMessages); 34 | 35 | Using(sharedCounter); 36 | 37 | // deliver a message for our endpoint 38 | network.CreateQueue(queueName); 39 | 40 | var client = GetOneWayClient(network, listLoggerFactory); 41 | 42 | numberOfMessages.Times(() => client.Advanced.Routing.Send(queueName, "HEJ MED DIG MIN VEN").Wait()); 43 | 44 | // prepare our endpoint 45 | var builder = new ContainerBuilder(); 46 | 47 | builder.RegisterRebus( 48 | config => config 49 | .Logging(l => l.Use(listLoggerFactory)) 50 | .Transport(t => t.UseInMemoryTransport(network, queueName)) 51 | .Options(o => 52 | { 53 | o.SetNumberOfWorkers(1); 54 | o.SetMaxParallelism(30); 55 | }) 56 | ); 57 | // obtain bus instance for subscriptions... 58 | builder.RegisterBuildCallback(c => { 59 | var bus = c.Resolve(); 60 | }); 61 | 62 | builder.RegisterHandler(); 63 | 64 | builder.RegisterInstance(sharedCounter); 65 | 66 | // start it 67 | using (builder.Build()) 68 | { 69 | sharedCounter.WaitForResetEvent(timeoutSeconds: 5); 70 | } 71 | 72 | // ensure no exceptions occurred 73 | 74 | Assert.That(listLoggerFactory.Count(log => log.Level >= LogLevel.Warn), Is.EqualTo(0), 75 | "Expected exactly ZERO warnings"); 76 | } 77 | 78 | IBus GetOneWayClient(InMemNetwork network, ListLoggerFactory listLoggerFactory) 79 | { 80 | var activator = new BuiltinHandlerActivator(); 81 | 82 | Using(activator); 83 | 84 | return Configure.With(activator) 85 | .Logging(l => l.Use(listLoggerFactory)) 86 | .Transport(t => t.UseInMemoryTransportAsOneWayClient(network)) 87 | .Start(); 88 | } 89 | 90 | class MyMessageHandler : IHandleMessages 91 | { 92 | readonly SharedCounter _sharedCounter; 93 | 94 | public MyMessageHandler(SharedCounter sharedCounter) => _sharedCounter = sharedCounter; 95 | 96 | public async Task Handle(string message) => _sharedCounter.Decrement(); 97 | } 98 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/Bugs/RegistersHandlerAsImplementationOfIFailedForDerivedMessagesToo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Autofac; 7 | using Autofac.Features.Variance; 8 | using NUnit.Framework; 9 | using Rebus.Bus; 10 | using Rebus.Config; 11 | using Rebus.Handlers; 12 | using Rebus.Retry; 13 | using Rebus.Retry.Simple; 14 | using Rebus.Tests.Contracts; 15 | using Rebus.Transport; 16 | using Rebus.Transport.InMem; 17 | #pragma warning disable 1998 18 | 19 | namespace Rebus.Autofac.Tests.Bugs; 20 | 21 | [TestFixture] 22 | public class RegistersHandlerAsImplementationOfIFailedForDerivedMessagesToo : FixtureBase 23 | { 24 | private class BaseMessage 25 | { 26 | } 27 | 28 | private class DerivedMessage : BaseMessage 29 | { 30 | } 31 | 32 | [Test, Description("Verifies that a bus using Autofac and Rebus' handler registration API CAN in fact received failed messages")] 33 | public async Task DoItWithTheBus() 34 | { 35 | var builder = new ContainerBuilder(); 36 | 37 | builder.RegisterSource(new ContravariantRegistrationSource()); 38 | 39 | builder.RegisterRebus(configurer => configurer 40 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "2nd-level-test")) 41 | .Options(o => o.RetryStrategy( 42 | secondLevelRetriesEnabled: true, 43 | maxDeliveryAttempts: 1 44 | )) 45 | ); 46 | 47 | builder.RegisterHandler(); 48 | 49 | var failedMessageWasReceived = new ManualResetEvent(false); 50 | 51 | builder.RegisterInstance(failedMessageWasReceived); 52 | 53 | using (var container = builder.Build()) 54 | { 55 | await container.Resolve().SendLocal(new DerivedMessage()); 56 | 57 | if (!failedMessageWasReceived.WaitOne(TimeSpan.FromSeconds(5))) 58 | { 59 | throw new AssertionException("Failed message was NOT received within 5s timeout!"); 60 | } 61 | } 62 | } 63 | 64 | class SecondLevelHandler : IHandleMessages, IHandleMessages> 65 | { 66 | readonly ManualResetEvent _gotTheFailedMessage; 67 | 68 | public SecondLevelHandler(ManualResetEvent gotTheFailedMessage) => _gotTheFailedMessage = gotTheFailedMessage; 69 | 70 | public Task Handle(BaseMessage message) => throw new NotImplementedException("MUAHAHAHAHAHA"); 71 | 72 | public async Task Handle(IFailed message) => _gotTheFailedMessage.Set(); 73 | } 74 | 75 | [Test] 76 | [Ignore("This logic is implemented in AutofacHandlerActivator as some additional logic, which is triggered when a message compatible with IFailed is detected")] 77 | public async Task ReadTheFixtureName() 78 | { 79 | var builder = new ContainerBuilder(); 80 | 81 | builder.RegisterHandler(); 82 | 83 | builder.RegisterSource(new ContravariantRegistrationSource()); 84 | 85 | using (var container = builder.Build()) 86 | { 87 | var ordinaryHandlers = container.Resolve>>(); 88 | var failedMessageHandlers = container.Resolve>>>(); 89 | 90 | Assert.That(ordinaryHandlers.Count(), Is.EqualTo(1)); 91 | Assert.That(failedMessageHandlers.Count(), Is.EqualTo(1)); 92 | } 93 | } 94 | 95 | [Test] 96 | public async Task ResolvesFailedOfBaseClass_FailedMessageWrapper() 97 | { 98 | var builder = new ContainerBuilder(); 99 | builder.RegisterSource(new ContravariantRegistrationSource()); 100 | builder.RegisterHandler(); 101 | 102 | var activator = new AutofacHandlerActivator(builder, (_, __) => { }, startBus: false, enablePolymorphicDispatch: true, multipleRegistrationsCheckEnabled: true); 103 | using (var container = builder.Build()) 104 | using (var scope = new RebusTransactionScope()) 105 | { 106 | var handlers = await activator.GetHandlers(null, scope.TransactionContext); 107 | Assert.That(handlers, Is.Not.Empty, "resolving handlers for derived messages failed"); 108 | 109 | var handlersFailed = await activator.GetHandlers>(null, scope.TransactionContext); 110 | Assert.That(handlersFailed, Is.Not.Empty, "resolving handlers for failed derived messages failed"); 111 | } 112 | } 113 | 114 | [Test] 115 | public async Task ResolvesFailedOfBaseClass_SpecialWrapper() 116 | { 117 | var builder = new ContainerBuilder(); 118 | builder.RegisterSource(new ContravariantRegistrationSource()); 119 | builder.RegisterHandler(); 120 | 121 | var activator = new AutofacHandlerActivator(builder, (_, __) => { }, startBus: false, enablePolymorphicDispatch: true, multipleRegistrationsCheckEnabled: true); 122 | using (var container = builder.Build()) 123 | using (var scope = new RebusTransactionScope()) 124 | { 125 | var handlers = await activator.GetHandlers(null, scope.TransactionContext); 126 | Assert.That(handlers, Is.Not.Empty, "resolving handlers for derived messages failed"); 127 | 128 | var handlersFailed = await activator.GetHandlers(null, scope.TransactionContext); 129 | Assert.That(handlersFailed, Is.Not.Empty, "resolving handlers for failed derived messages failed"); 130 | } 131 | } 132 | 133 | [Test] 134 | public async Task ResolvesFailedOfBaseClass_FailedInterface() 135 | { 136 | var builder = new ContainerBuilder(); 137 | builder.RegisterSource(new ContravariantRegistrationSource()); 138 | builder.RegisterHandler(); 139 | 140 | var activator = new AutofacHandlerActivator(builder, (_, __) => { }, startBus: false, enablePolymorphicDispatch: true, multipleRegistrationsCheckEnabled: true); 141 | using (var container = builder.Build()) 142 | using (var scope = new RebusTransactionScope()) 143 | { 144 | var handlers = await activator.GetHandlers(null, scope.TransactionContext); 145 | Assert.That(handlers, Is.Not.Empty, "resolving handlers for derived messages failed"); 146 | 147 | var handlersFailed = await activator.GetHandlers>(null, scope.TransactionContext); 148 | Assert.That(handlersFailed, Is.Not.Empty, "resolving handlers for failed derived messages failed"); 149 | } 150 | } 151 | 152 | private class SpecialFailedMessage : IFailed 153 | { 154 | public DerivedMessage Message { get; set; } 155 | public string ErrorDescription { get; } 156 | public Dictionary Headers { get; set; } 157 | public IEnumerable Exceptions { get; set; } 158 | } 159 | 160 | public class FailedMessage : IFailed 161 | { 162 | public FailedMessage(T message, string errorDescription, Dictionary headers, IEnumerable exceptions) 163 | { 164 | Message = message; 165 | ErrorDescription = errorDescription; 166 | Headers = headers; 167 | Exceptions = exceptions; 168 | } 169 | 170 | public T Message { get; } 171 | public string ErrorDescription { get; } 172 | public Dictionary Headers { get; } 173 | public IEnumerable Exceptions { get; } 174 | } 175 | 176 | class TestHandler : IHandleMessages, IHandleMessages> 177 | { 178 | public Task Handle(BaseMessage message) 179 | { 180 | throw new System.NotImplementedException(); 181 | } 182 | 183 | public Task Handle(IFailed message) 184 | { 185 | throw new System.NotImplementedException(); 186 | } 187 | } 188 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/Bugs/RegistersHandlerAsImplementationOfIFailedToo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Autofac; 7 | using Autofac.Features.Variance; 8 | using NUnit.Framework; 9 | using Rebus.Bus; 10 | using Rebus.Config; 11 | using Rebus.Handlers; 12 | using Rebus.Retry; 13 | using Rebus.Retry.Simple; 14 | using Rebus.Tests.Contracts; 15 | using Rebus.Transport; 16 | using Rebus.Transport.InMem; 17 | #pragma warning disable 1998 18 | 19 | namespace Rebus.Autofac.Tests.Bugs; 20 | 21 | [TestFixture] 22 | public class RegistersHandlerAsImplementationOfIFailedToo : FixtureBase 23 | { 24 | [Test, Description("Verifies that a bus using Autofac and Rebus' handler registration API CAN in fact received failed messages")] 25 | public async Task DoItWithTheBus() 26 | { 27 | var builder = new ContainerBuilder(); 28 | 29 | builder.RegisterSource(new ContravariantRegistrationSource()); 30 | 31 | builder.RegisterRebus(configurer => configurer 32 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "2nd-level-test")) 33 | .Options(o => o.RetryStrategy( 34 | secondLevelRetriesEnabled: true, 35 | maxDeliveryAttempts: 1 36 | )) 37 | ); 38 | 39 | builder.RegisterHandler(); 40 | 41 | var failedMessageWasReceived = new ManualResetEvent(false); 42 | 43 | builder.RegisterInstance(failedMessageWasReceived); 44 | 45 | using (var container = builder.Build()) 46 | { 47 | await container.Resolve().SendLocal("HEJ MED DIG MIN VEN"); 48 | 49 | if (!failedMessageWasReceived.WaitOne(TimeSpan.FromSeconds(5))) 50 | { 51 | throw new AssertionException("Failed message was NOT received within 5s timeout!"); 52 | } 53 | } 54 | } 55 | 56 | class SecondLevelHandler : IHandleMessages, IHandleMessages> 57 | { 58 | readonly ManualResetEvent _gotTheFailedMessage; 59 | 60 | public SecondLevelHandler(ManualResetEvent gotTheFailedMessage) => _gotTheFailedMessage = gotTheFailedMessage; 61 | 62 | public Task Handle(string message) => throw new NotImplementedException("MUAHAHAHAHAHA"); 63 | 64 | public async Task Handle(IFailed message) => _gotTheFailedMessage.Set(); 65 | } 66 | 67 | [Test] 68 | public async Task ReadTheFixtureName() 69 | { 70 | var builder = new ContainerBuilder(); 71 | 72 | builder.RegisterHandler(); 73 | 74 | using (var container = builder.Build()) 75 | { 76 | var ordinaryHandlers = container.Resolve>>(); 77 | var failedMessageHandlers = container.Resolve>>>(); 78 | 79 | Assert.That(ordinaryHandlers.Count(), Is.EqualTo(1)); 80 | Assert.That(failedMessageHandlers.Count(), Is.EqualTo(1)); 81 | } 82 | } 83 | 84 | [Test] 85 | public async Task ResolvesFailedOfBaseClass() 86 | { 87 | var builder = new ContainerBuilder(); 88 | builder.RegisterHandler(); 89 | 90 | var activator = new AutofacHandlerActivator(builder, (_, __) => { }, startBus: false, enablePolymorphicDispatch: true, multipleRegistrationsCheckEnabled: true); 91 | using (var container = builder.Build()) 92 | using (var scope = new RebusTransactionScope()) 93 | { 94 | var handlers = await activator.GetHandlers(null, scope.TransactionContext); 95 | Assert.That(handlers, Is.Not.Empty, "resolving handlers for derived messages failed"); 96 | 97 | var handlersFailed = await activator.GetHandlers>(null, scope.TransactionContext); 98 | Assert.That(handlersFailed, Is.Not.Empty, "resolving handlers for failed derived messages failed"); 99 | } 100 | } 101 | 102 | public class FailedMessage : IFailed 103 | { 104 | public FailedMessage(T message, string errorDescription, Dictionary headers, IEnumerable exceptions) 105 | { 106 | Message = message; 107 | ErrorDescription = errorDescription; 108 | Headers = headers; 109 | Exceptions = exceptions; 110 | } 111 | 112 | public T Message { get; } 113 | public string ErrorDescription { get; } 114 | public Dictionary Headers { get; } 115 | public IEnumerable Exceptions { get; } 116 | } 117 | 118 | class TestHandler : IHandleMessages, IHandleMessages> 119 | { 120 | public Task Handle(string message) 121 | { 122 | throw new System.NotImplementedException(); 123 | } 124 | 125 | public Task Handle(IFailed message) 126 | { 127 | throw new System.NotImplementedException(); 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/Bugs/ReproduceDoubleDispatchIssue.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Threading.Tasks; 4 | using AdditionalHandlerAssembly; 5 | using Autofac; 6 | using NUnit.Framework; 7 | using Rebus.Bus; 8 | using Rebus.Config; 9 | using Rebus.Retry.Simple; 10 | using Rebus.Tests.Contracts; 11 | using Rebus.Tests.Contracts.Extensions; 12 | using Rebus.Transport.InMem; 13 | 14 | namespace Rebus.Autofac.Tests.Bugs; 15 | 16 | [TestFixture] 17 | public class ReproduceDoubleDispatchIssue : FixtureBase 18 | { 19 | [Test] 20 | [Description("Tried to reproduce issue reported: Messages should apparently be dispatched twice. Sp far, reproduction has not been not successful.")] 21 | public async Task ItWorks() 22 | { 23 | var controllerChangeMessages = new ConcurrentQueue(); 24 | 25 | var builder = new ContainerBuilder(); 26 | 27 | builder.RegisterRebus((configurer, _) => 28 | { 29 | var queueName = "queue"; 30 | 31 | configurer 32 | .Logging(l => l.ColoredConsole()) 33 | .Transport(x => x.UseInMemoryTransport(new InMemNetwork(true), queueName)) 34 | .Options(x => 35 | { 36 | x.SetMaxParallelism(1); 37 | x.RetryStrategy(maxDeliveryAttempts: int.MaxValue); 38 | }); 39 | 40 | return configurer; 41 | }); 42 | 43 | builder.RegisterHandlersFromAssemblyOf(); 44 | 45 | builder.RegisterInstance(controllerChangeMessages).AsSelf(); 46 | 47 | await using var container = builder.Build(); 48 | 49 | var bus = container.Resolve(); 50 | 51 | await bus.SendLocal(new ControllerChangeMessage()); 52 | 53 | // wait for at least one message to arrive 54 | await controllerChangeMessages.WaitUntil(q => q.Count >= 1); 55 | 56 | // wait additional time to be sure all messages have been processed 57 | await Task.Delay(TimeSpan.FromSeconds(2)); 58 | 59 | // even at this point, the handler should only have been called once! 60 | Assert.That(controllerChangeMessages.Count, Is.EqualTo(1)); 61 | } 62 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/CheckNewApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Autofac; 3 | using NUnit.Framework; 4 | using Rebus.Bus; 5 | using Rebus.Config; 6 | using Rebus.Logging; 7 | using Rebus.Tests.Contracts; 8 | using Rebus.Tests.Contracts.Utilities; 9 | using Rebus.Transport.InMem; 10 | // ReSharper disable RedundantArgumentDefaultValue 11 | // ReSharper disable ArgumentsStyleNamedExpression 12 | 13 | namespace Rebus.Autofac.Tests; 14 | 15 | [TestFixture] 16 | public class CheckNewApi : FixtureBase 17 | { 18 | [Test] 19 | public void ThisIsHowItWorks_StartsAutomatically() 20 | { 21 | var builder = new ContainerBuilder(); 22 | 23 | builder.RegisterRebus( 24 | configure => configure 25 | .Logging(l => l.Console(minLevel: LogLevel.Debug)) 26 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test")) 27 | ); 28 | 29 | var container = builder.Build(); 30 | 31 | Using(container); 32 | 33 | var bus = container.Resolve(); 34 | 35 | Assert.That(bus.Advanced.Workers.Count, Is.EqualTo(1)); 36 | } 37 | 38 | [Test] 39 | public void ThisIsHowItWorks_StartManually() 40 | { 41 | var builder = new ContainerBuilder(); 42 | 43 | builder.RegisterRebus( 44 | configure => configure 45 | .Logging(l => l.Console(minLevel: LogLevel.Debug)) 46 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test")), 47 | 48 | startAutomatically: false 49 | ); 50 | 51 | var container = builder.Build(); 52 | 53 | Using(container); 54 | 55 | var bus = container.Resolve(); 56 | 57 | Assert.That(bus.Advanced.Workers.Count, Is.EqualTo(0)); 58 | 59 | container.StartBus(); 60 | 61 | Assert.That(bus.Advanced.Workers.Count, Is.EqualTo(1)); 62 | } 63 | 64 | [Test] 65 | public void ThisIsHowItWorks() 66 | { 67 | var builder = new ContainerBuilder(); 68 | 69 | builder.RegisterRebus( 70 | configure => configure 71 | .Logging(l => l.Console(minLevel: LogLevel.Debug)) 72 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test")) 73 | ); 74 | 75 | var container = builder.Build(); 76 | 77 | Using(container); 78 | } 79 | 80 | [Test] 81 | public void ThisIsHowItWorks_ComponentContext() 82 | { 83 | var builder = new ContainerBuilder(); 84 | 85 | builder.Register(_ => new ListLoggerFactory(outputToConsole: true)); 86 | 87 | builder.RegisterRebus( 88 | (configure, context) => configure 89 | .Logging(l => l.Use(context.Resolve())) 90 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test")) 91 | ); 92 | 93 | var container = builder.Build(); 94 | 95 | Using(container); 96 | } 97 | 98 | [Test] 99 | public void ThrowsWhenAddingTwice() 100 | { 101 | var builder = new ContainerBuilder(); 102 | 103 | builder.RegisterRebus(configure => configure 104 | .Logging(l => l.Console(minLevel: LogLevel.Debug)) 105 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test"))); 106 | 107 | builder.RegisterRebus(configure => configure 108 | .Logging(l => l.Console(minLevel: LogLevel.Debug)) 109 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test"))); 110 | 111 | Assert.Throws(() => builder.Build()); 112 | } 113 | 114 | [Test] 115 | public void DoesNotThrowWhenRegisteringTwiceIfExplicitlyDisabled() 116 | { 117 | var builder = new ContainerBuilder(); 118 | 119 | builder.RegisterRebus(configure => configure 120 | .Logging(l => l.Console(minLevel: LogLevel.Debug)) 121 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test")), 122 | disableMultipleRegistrationsCheck: true); 123 | 124 | builder.RegisterRebus(configure => configure 125 | .Logging(l => l.Console(minLevel: LogLevel.Debug)) 126 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "ioc-test")), 127 | disableMultipleRegistrationsCheck: true); 128 | 129 | Assert.DoesNotThrow(() => builder.Build()); 130 | } 131 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/CheckResolutionPerformance.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Autofac; 7 | using NUnit.Framework; 8 | using Rebus.Config; 9 | using Rebus.Handlers; 10 | using Rebus.Transport; 11 | // ReSharper disable ArgumentsStyleLiteral 12 | 13 | namespace Rebus.Autofac.Tests; 14 | 15 | [TestFixture] 16 | public class CheckResolutionPerformance 17 | { 18 | /* 19 | Initially: 20 | 21 | 22 | Running 10 samples of 1000000 iterations 23 | Running sample # 1 24 | Running sample # 2 25 | Running sample # 3 26 | Running sample # 4 27 | Running sample # 5 28 | Running sample # 6 29 | Running sample # 7 30 | Running sample # 8 31 | Running sample # 9 32 | Running sample # 10 33 | Results: 34 | 35 | 5,088 s 36 | 4,909 s 37 | 4,677 s 38 | 4,668 s 39 | 4,524 s 40 | 4,500 s 41 | 4,477 s 42 | 4,457 s 43 | 4,466 s 44 | 4,482 s 45 | 46 | AVG: 4,625 47 | 48 | After caching types to resolve in ConcurrentDictionary: 49 | 50 | 51 | Running 10 samples of 1000000 iterations 52 | Running sample # 1 53 | Running sample # 2 54 | Running sample # 3 55 | Running sample # 4 56 | Running sample # 5 57 | Running sample # 6 58 | Running sample # 7 59 | Running sample # 8 60 | Running sample # 9 61 | Running sample # 10 62 | Results: 63 | 64 | 4,312 s 65 | 4,274 s 66 | 4,282 s 67 | 4,466 s 68 | 4,450 s 69 | 4,593 s 70 | 4,291 s 71 | 4,256 s 72 | 4,548 s 73 | 4,470 s 74 | 75 | AVG: 4,394 76 | 77 | 78 | Refactor to local functions and collapsed typecast into one single cast: 79 | 80 | 81 | Running 10 samples of 1000000 iterations 82 | Running sample # 1 83 | Running sample # 2 84 | Running sample # 3 85 | Running sample # 4 86 | Running sample # 5 87 | Running sample # 6 88 | Running sample # 7 89 | Running sample # 8 90 | Running sample # 9 91 | Running sample # 10 92 | Results: 93 | 94 | 3,906 s 95 | 3,905 s 96 | 3,911 s 97 | 3,883 s 98 | 3,899 s 99 | 3,893 s 100 | 4,668 s 101 | 4,027 s 102 | 4,017 s 103 | 4,147 s 104 | 105 | AVG: 4,026 106 | 107 | 108 | 109 | */ 110 | [TestCase(10, 1000000)] 111 | [TestCase(10, 10000)] 112 | [Explicit("takes a long time")] 113 | public async Task Run(int samples, int ops) 114 | { 115 | Console.WriteLine($"Running {samples} samples of {ops} iterations"); 116 | 117 | var builder = new ContainerBuilder(); 118 | 119 | builder.RegisterHandler(); 120 | builder.RegisterHandler(); 121 | builder.RegisterHandler(); 122 | 123 | var activator = new AutofacHandlerActivator(builder, (_, _) => { }, startBus: false, enablePolymorphicDispatch: true, multipleRegistrationsCheckEnabled: true); 124 | var timeSpans = new List(); 125 | 126 | await using (builder.Build()) 127 | { 128 | foreach (var sample in Enumerable.Range(1, samples)) 129 | { 130 | var elapsed = await TakeSample(sample, ops, activator); 131 | 132 | timeSpans.Add(elapsed); 133 | } 134 | } 135 | 136 | Console.WriteLine($@"Results: 137 | 138 | {string.Join(Environment.NewLine, timeSpans.Select(t => $" {t.TotalSeconds:0.000} s"))} 139 | 140 | AVG: {timeSpans.Select(t => t.TotalSeconds).Average():0.000}"); 141 | } 142 | 143 | static async Task TakeSample(int sample, int ops, AutofacHandlerActivator activator) 144 | { 145 | Console.WriteLine($"Running sample # {sample}"); 146 | 147 | var stopwatch = Stopwatch.StartNew(); 148 | 149 | for (var counter = 0; counter < ops; counter++) 150 | { 151 | using (var scope = new RebusTransactionScope()) 152 | { 153 | var handlers1 = await activator.GetHandlers(new OrdinaryMessage(), scope.TransactionContext); 154 | } 155 | 156 | using (var scope = new RebusTransactionScope()) 157 | { 158 | var handlers2 = await activator.GetHandlers(new PolymorphicMessage(), scope.TransactionContext); 159 | } 160 | } 161 | 162 | return stopwatch.Elapsed; 163 | } 164 | 165 | class OrdinaryMessage { } 166 | 167 | class OrdinaryMessageHandler : IHandleMessages 168 | { 169 | public Task Handle(OrdinaryMessage message) 170 | { 171 | throw new NotImplementedException(); 172 | } 173 | } 174 | 175 | class PolymorphicMessage { } 176 | 177 | class PolymorphicMessageHandler : IHandleMessages 178 | { 179 | public Task Handle(PolymorphicMessage message) 180 | { 181 | throw new NotImplementedException(); 182 | } 183 | } 184 | 185 | class PolymorphicMessageHandler2 : IHandleMessages 186 | { 187 | public Task Handle(object message) 188 | { 189 | throw new NotImplementedException(); 190 | } 191 | } 192 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/Rebus.Autofac.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net8.0 4 | 11 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/TestAutofacAssumptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Autofac; 4 | using NUnit.Framework; 5 | 6 | namespace Rebus.Autofac.Tests; 7 | 8 | [TestFixture] 9 | public class TestAutofacAssumptions 10 | { 11 | [Test] 12 | public void CanResolveLotsOfStuff() 13 | { 14 | var builder = new ContainerBuilder(); 15 | 16 | builder.RegisterType().As(typeof (ISomething)).InstancePerDependency(); 17 | builder.RegisterType().As(typeof (ISomething)).InstancePerDependency(); 18 | 19 | var container = builder.Build(); 20 | 21 | var somethings = container.Resolve>().ToArray(); 22 | 23 | Assert.That(somethings.Length, Is.EqualTo(2)); 24 | } 25 | 26 | interface ISomething { } 27 | 28 | class Impl11 : ISomething { } 29 | class Impl12 : ISomething { } 30 | } -------------------------------------------------------------------------------- /Rebus.Autofac.Tests/TestRegistrationApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Autofac; 6 | using MessageHandlers; 7 | using NUnit.Framework; 8 | using Rebus.Bus; 9 | using Rebus.Config; 10 | using Rebus.Handlers; 11 | using Rebus.Transport.InMem; 12 | // ReSharper disable ClassNeverInstantiated.Local 13 | 14 | namespace Rebus.Autofac.Tests; 15 | 16 | [TestFixture] 17 | public class TestRegistrationApi 18 | { 19 | [Test] 20 | public void ItWorks_Single() 21 | { 22 | var builder = new ContainerBuilder(); 23 | 24 | builder.RegisterHandler(); 25 | 26 | using var container = builder.Build(); 27 | 28 | var stringHandlers = container.Resolve>>().ToList(); 29 | 30 | Assert.That(stringHandlers.Count, Is.EqualTo(1)); 31 | Assert.That(stringHandlers[0], Is.TypeOf()); 32 | } 33 | 34 | class MsgHndlr : IHandleMessages 35 | { 36 | public Task Handle(string message) => throw new NotImplementedException(); 37 | } 38 | 39 | [Test] 40 | public void ItWorks_Multiple() 41 | { 42 | var builder = new ContainerBuilder(); 43 | 44 | builder.RegisterType().SingleInstance(); 45 | builder.RegisterHandlersFromAssemblyOf(); 46 | 47 | using var container = builder.Build(); 48 | 49 | var stringHandlers = container.Resolve>>().ToList(); 50 | 51 | Assert.That(stringHandlers.Count, Is.EqualTo(2)); 52 | } 53 | 54 | [Test] 55 | public async Task RealBusAndStuff_Single() 56 | { 57 | var builder = new ContainerBuilder(); 58 | 59 | builder.RegisterHandler(); 60 | builder.RegisterHandler(); 61 | 62 | builder.RegisterType().SingleInstance(); 63 | builder.RegisterRebus( 64 | configurer => configurer 65 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "doesn't matter")) 66 | .Options(o => 67 | { 68 | o.SetNumberOfWorkers(1); 69 | o.SetMaxParallelism(1); 70 | }) 71 | ); 72 | 73 | await using var container = builder.Build(); 74 | 75 | var bus = container.Resolve(); 76 | 77 | await bus.SendLocal("HEJ MED DIG"); 78 | await bus.SendLocal("HVORDAN GÅR DET?"); 79 | 80 | await Task.Delay(500); 81 | 82 | var events = container.Resolve().ToList(); 83 | 84 | Assert.That(events.Count, Is.EqualTo(4)); 85 | Console.WriteLine(string.Join(Environment.NewLine, events)); 86 | } 87 | 88 | [Test] 89 | public async Task RealBusAndStuff_Multiple() 90 | { 91 | var builder = new ContainerBuilder(); 92 | 93 | builder.RegisterHandlersFromAssemblyOf(); 94 | 95 | builder.RegisterType().SingleInstance(); 96 | builder.RegisterRebus( 97 | configurer => configurer 98 | .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "doesn't matter")) 99 | .Options(o => 100 | { 101 | o.SetNumberOfWorkers(1); 102 | o.SetMaxParallelism(1); 103 | }) 104 | ); 105 | 106 | await using var container = builder.Build(); 107 | 108 | var bus = container.Resolve(); 109 | 110 | await bus.SendLocal("HEJ MED DIG"); 111 | await bus.SendLocal("HVORDAN GÅR DET?"); 112 | 113 | await Task.Delay(500); 114 | 115 | var events = container.Resolve().ToList(); 116 | 117 | Assert.That(events.Count, Is.EqualTo(4)); 118 | Console.WriteLine(string.Join(Environment.NewLine, events)); 119 | } 120 | } -------------------------------------------------------------------------------- /Rebus.Autofac.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 16 3 | VisualStudioVersion = 16.0.29709.97 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "stuff", "stuff", "{1ABDD7C1-1F8D-402D-8692-3E4B66962DE0}" 6 | ProjectSection(SolutionItems) = preProject 7 | appveyor.yml = appveyor.yml 8 | CHANGELOG.md = CHANGELOG.md 9 | CONTRIBUTING.md = CONTRIBUTING.md 10 | LICENSE.md = LICENSE.md 11 | README.md = README.md 12 | EndProjectSection 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rebus.Autofac", "Rebus.Autofac\Rebus.Autofac.csproj", "{EFD356C6-D187-4064-A13A-2BF6BA2B3425}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rebus.Autofac.Tests", "Rebus.Autofac.Tests\Rebus.Autofac.Tests.csproj", "{1D0F14F3-4BB1-40D0-AAE2-550A34B10290}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MessageHandlers", "MessageHandlers\MessageHandlers.csproj", "{A40C0086-BEEA-4205-8BEA-3B3164A245A8}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdditionalHandlerAssembly", "AdditionalHandlerAssembly\AdditionalHandlerAssembly.csproj", "{C6161934-6663-4743-9844-0A148B4FD590}" 21 | EndProject 22 | Global 23 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 24 | Debug|Any CPU = Debug|Any CPU 25 | Release|Any CPU = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 28 | {EFD356C6-D187-4064-A13A-2BF6BA2B3425}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {EFD356C6-D187-4064-A13A-2BF6BA2B3425}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {EFD356C6-D187-4064-A13A-2BF6BA2B3425}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {EFD356C6-D187-4064-A13A-2BF6BA2B3425}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {1D0F14F3-4BB1-40D0-AAE2-550A34B10290}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {1D0F14F3-4BB1-40D0-AAE2-550A34B10290}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {1D0F14F3-4BB1-40D0-AAE2-550A34B10290}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {1D0F14F3-4BB1-40D0-AAE2-550A34B10290}.Release|Any CPU.Build.0 = Release|Any CPU 36 | {A40C0086-BEEA-4205-8BEA-3B3164A245A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {A40C0086-BEEA-4205-8BEA-3B3164A245A8}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {A40C0086-BEEA-4205-8BEA-3B3164A245A8}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {A40C0086-BEEA-4205-8BEA-3B3164A245A8}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {C6161934-6663-4743-9844-0A148B4FD590}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {C6161934-6663-4743-9844-0A148B4FD590}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {C6161934-6663-4743-9844-0A148B4FD590}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {C6161934-6663-4743-9844-0A148B4FD590}.Release|Any CPU.Build.0 = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {03DE8B23-BAD7-4666-A219-E3A65F000895} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /Rebus.Autofac/Autofac/AutofacHandlerActivator.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Autofac.Core; 3 | using Autofac.Features.Variance; 4 | using Rebus.Activation; 5 | using Rebus.Bus; 6 | using Rebus.Config; 7 | using Rebus.Exceptions; 8 | using Rebus.Handlers; 9 | using Rebus.Internals; 10 | using Rebus.Pipeline; 11 | using Rebus.Retry.Simple; 12 | using Rebus.Transport; 13 | using System; 14 | using System.Collections.Concurrent; 15 | using System.Collections.Generic; 16 | using System.Linq; 17 | using System.Threading.Tasks; 18 | // ReSharper disable SimplifyLinqExpressionUseAll 19 | #pragma warning disable 1998 20 | 21 | namespace Rebus.Autofac; 22 | 23 | class AutofacHandlerActivator : IHandlerActivator 24 | { 25 | const string LongExceptionMessage = 26 | "This particular container builder seems to have had the RegisterRebus(...) extension called on it more than once, which is unfortunately not allowed. In some cases, this is simply an indication that the configuration code for some reason has been executed more than once, which is probably not intended. If you intended to use one Autofac container to host multiple Rebus instances, please consider using a separate container instance for each Rebus endpoint that you wish to start."; 27 | 28 | readonly ConcurrentDictionary>> _resolvers = new(); 29 | 30 | ILifetimeScope _container; 31 | 32 | public AutofacHandlerActivator(ContainerBuilder containerBuilder, Action configureBus, bool startBus, bool enablePolymorphicDispatch, bool multipleRegistrationsCheckEnabled) 33 | { 34 | if (containerBuilder == null) throw new ArgumentNullException(nameof(containerBuilder)); 35 | if (configureBus == null) throw new ArgumentNullException(nameof(configureBus)); 36 | 37 | if (enablePolymorphicDispatch) 38 | { 39 | containerBuilder.RegisterSource(new ContravariantRegistrationSource()); 40 | } 41 | 42 | if (multipleRegistrationsCheckEnabled) 43 | { 44 | var autofacHandlerActivatorWasRegistered = false; 45 | 46 | // guard against additional calls to RegisterRebus by detecting number of calls here 47 | containerBuilder.ComponentRegistryBuilder.Registered += (_, ea) => 48 | { 49 | var registration = ea.ComponentRegistration; 50 | var typedServices = registration.Services.OfType(); 51 | 52 | if (!typedServices.Any(t => t.ServiceType == typeof(AutofacHandlerActivator))) return; 53 | 54 | if (autofacHandlerActivatorWasRegistered) 55 | { 56 | throw new InvalidOperationException(LongExceptionMessage); 57 | } 58 | 59 | autofacHandlerActivatorWasRegistered = true; 60 | }; 61 | } 62 | 63 | // Register autofac starter 64 | containerBuilder.RegisterInstance(this).As() 65 | .AutoActivate() 66 | .SingleInstance() 67 | .OnActivated(e => 68 | { 69 | e.Instance._container ??= e.Context.Resolve(); 70 | 71 | if (!startBus) return; 72 | 73 | // Start the bus up if requested 74 | try 75 | { 76 | var busStarter = e.Context.Resolve(); 77 | 78 | busStarter.Start(); 79 | } 80 | catch (Exception exception) 81 | { 82 | throw new RebusConfigurationException(exception, "Could not start Rebus"); 83 | } 84 | }); 85 | 86 | // Register IBusStarter 87 | containerBuilder 88 | .Register(context => 89 | { 90 | _container ??= context.Resolve(); 91 | 92 | var rebusConfigurer = Configure.With(this); 93 | configureBus.Invoke(rebusConfigurer, context); 94 | return rebusConfigurer.Create(); 95 | }) 96 | .SingleInstance(); 97 | 98 | // Register IBus 99 | containerBuilder 100 | .Register(context => context.Resolve().Bus) 101 | .SingleInstance(); 102 | 103 | // Register ISyncBus, resolved from IBus 104 | containerBuilder 105 | .Register(c => c.Resolve().Advanced.SyncBus) 106 | .InstancePerDependency() 107 | .ExternallyOwned(); 108 | 109 | // Register IMessageContext 110 | containerBuilder 111 | .Register(_ => 112 | { 113 | var messageContext = MessageContext.Current; 114 | if (messageContext == null) 115 | { 116 | throw new InvalidOperationException("MessageContext.Current was null, which probably means that IMessageContext was resolved outside of a Rebus message handler transaction"); 117 | } 118 | return messageContext; 119 | }) 120 | .InstancePerDependency() 121 | .ExternallyOwned(); 122 | } 123 | 124 | /// 125 | /// Resolves all handlers for the given message type 126 | /// 127 | public async Task>> GetHandlers(TMessage message, ITransactionContext transactionContext) 128 | { 129 | ILifetimeScope CreateLifetimeScope() 130 | { 131 | var scope = _container.BeginLifetimeScope(); 132 | transactionContext.OnDisposed(_ => scope.Dispose()); 133 | return scope; 134 | } 135 | 136 | Func> GetResolveForMessageType(Type messageType) 137 | { 138 | if (messageType.IsAssignableTo(typeof(IFailed<>))) 139 | { 140 | var containedMessageType = messageType.GetGenericTypeParameters(typeof(IFailed<>)).Single(); 141 | var additionalTypesToResolveHandlersFor = containedMessageType.GetBaseTypes(includeSelf: false); 142 | var typesToResolve = new[] { containedMessageType }.Concat(additionalTypesToResolveHandlersFor) 143 | .Select(type => typeof(IEnumerable<>).MakeGenericType(typeof(IHandleMessages<>).MakeGenericType(typeof(IFailed<>).MakeGenericType(type)))) 144 | .ToArray(); 145 | 146 | return scope => 147 | { 148 | var handlers = new List>(); 149 | 150 | foreach (var type in typesToResolve) 151 | { 152 | handlers.AddRange((IEnumerable>)scope.Resolve(type)); 153 | } 154 | 155 | return handlers; 156 | }; 157 | } 158 | 159 | return scope => scope.Resolve>>(); 160 | } 161 | 162 | var lifetimeScope = transactionContext.GetOrAdd("current-autofac-lifetime-scope", CreateLifetimeScope); 163 | var resolver = _resolvers.GetOrAdd(typeof(TMessage), GetResolveForMessageType); 164 | 165 | return (IEnumerable>)resolver(lifetimeScope); 166 | } 167 | } -------------------------------------------------------------------------------- /Rebus.Autofac/Config/ContainerBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Autofac; 5 | using Rebus.Autofac; 6 | using Rebus.Handlers; 7 | // ReSharper disable ArgumentsStyleNamedExpression 8 | // ReSharper disable ArgumentsStyleLiteral 9 | // ReSharper disable ObjectCreationAsStatement 10 | // ReSharper disable UnusedMember.Global 11 | 12 | namespace Rebus.Config; 13 | 14 | /// 15 | /// Configuration extensions for helping with hooking Rebus up correctly for resolving handlers in Autofac 16 | /// 17 | public static class ContainerBuilderExtensions 18 | { 19 | /// 20 | /// Makes the necessary registrations in the given , invoking the 21 | /// callback when Rebus needs to be configured. You can only have a single 22 | /// bus and set of handlers registered within an Autofac IoC container. If you wish to have multiple handlers, you will need 23 | /// to split up the bus into a one way bus, and multiple handler registrations. 24 | /// 25 | public static void RegisterRebus(this ContainerBuilder containerBuilder, Func configure, bool startAutomatically = true, bool enablePolymorphicDispatch = false, bool disableMultipleRegistrationsCheck = false) 26 | { 27 | if (containerBuilder == null) throw new ArgumentNullException(nameof(containerBuilder)); 28 | if (configure == null) throw new ArgumentNullException(nameof(configure)); 29 | 30 | new AutofacHandlerActivator(containerBuilder, (configurer, _) => configure(configurer), startAutomatically, enablePolymorphicDispatch, !disableMultipleRegistrationsCheck); 31 | } 32 | 33 | /// 34 | /// Makes the necessary registrations in the given , invoking the 35 | /// callback when Rebus needs to be configured. You can only have a single 36 | /// bus and set of handlers registered within an Autofac IoC container. If you wish to have multiple handlers, you will need 37 | /// to split up the bus into a one way bus, and multiple handler registrations. 38 | /// 39 | public static void RegisterRebus(this ContainerBuilder containerBuilder, Func configure, bool startAutomatically = true, bool enablePolymorphicDispatch = false, bool disableMultipleRegistrationsCheck = false) 40 | { 41 | if (containerBuilder == null) throw new ArgumentNullException(nameof(containerBuilder)); 42 | if (configure == null) throw new ArgumentNullException(nameof(configure)); 43 | 44 | new AutofacHandlerActivator(containerBuilder, (configurer, context) => configure(configurer, context), startAutomatically, enablePolymorphicDispatch, !disableMultipleRegistrationsCheck); 45 | } 46 | 47 | /// 48 | /// Registers all Rebus message handler types found in the assembly of 49 | /// 50 | public static void RegisterHandlersFromAssemblyOf(this ContainerBuilder builder, PropertyWiringOptions propertyWiringOptions = PropertyWiringOptions.None) 51 | { 52 | RegisterHandlersFromAssemblyOf(builder, typeof(T), propertyWiringOptions); 53 | } 54 | 55 | /// 56 | /// Registers all Rebus message handler types found in the assembly of 57 | /// 58 | public static void RegisterHandlersFromAssemblyOf(this ContainerBuilder builder, Type handlerType, PropertyWiringOptions propertyWiringOptions = PropertyWiringOptions.None) 59 | { 60 | if (builder == null) throw new ArgumentNullException(nameof(builder)); 61 | if (handlerType == null) throw new ArgumentNullException(nameof(handlerType)); 62 | 63 | builder.RegisterAssemblyTypes(handlerType.Assembly) 64 | .Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Any(IsRebusHandler)) 65 | .As(GetImplementedHandlerInterfaces) 66 | .InstancePerDependency() 67 | .PropertiesAutowired(propertyWiringOptions); 68 | } 69 | 70 | /// 71 | /// Registers all Rebus message handler types found in the assembly of under the namespace that type lives 72 | /// under. So all types within the same namespace will get mapped as handlers, but not types under other namespaces. This allows 73 | /// you to separate messages for specific queues by namespace and register them all in one go. 74 | /// 75 | public static void RegisterHandlersFromAssemblyNamespaceOf(this ContainerBuilder builder, PropertyWiringOptions propertyWiringOptions = PropertyWiringOptions.None) 76 | { 77 | RegisterHandlersFromAssemblyNamespaceOf(builder, typeof(T), propertyWiringOptions); 78 | } 79 | 80 | /// 81 | /// Registers all Rebus message handler types found in the assembly of under the namespace that type lives 82 | /// under. So all types within the same namespace will get mapped as handlers, but not types under other namespaces. This allows 83 | /// you to separate messages for specific queues by namespace and register them all in one go. 84 | /// 85 | public static void RegisterHandlersFromAssemblyNamespaceOf(this ContainerBuilder builder, Type handlerType, PropertyWiringOptions propertyWiringOptions = PropertyWiringOptions.None) 86 | { 87 | if (builder == null) throw new ArgumentNullException(nameof(builder)); 88 | if (handlerType == null) throw new ArgumentNullException(nameof(handlerType)); 89 | 90 | builder.RegisterAssemblyTypes(handlerType.Assembly) 91 | .Where(t => t.IsClass && !t.IsAbstract && t.GetInterfaces().Any(IsRebusHandler) && t.Namespace != null && t.Namespace.StartsWith(handlerType.Namespace ?? string.Empty)) 92 | .As(GetImplementedHandlerInterfaces) 93 | .InstancePerDependency() 94 | .PropertiesAutowired(propertyWiringOptions); 95 | } 96 | 97 | /// 98 | /// Registers the given type as a Rebus message handler 99 | /// 100 | public static void RegisterHandler(this ContainerBuilder builder, PropertyWiringOptions propertyWiringOptions = PropertyWiringOptions.None) where THandler : IHandleMessages 101 | { 102 | if (builder == null) throw new ArgumentNullException(nameof(builder)); 103 | 104 | var implementedHandlerTypes = GetImplementedHandlerInterfaces(typeof(THandler)).ToArray(); 105 | 106 | builder.RegisterType(typeof(THandler)).As(implementedHandlerTypes) 107 | .InstancePerDependency() 108 | .PropertiesAutowired(propertyWiringOptions); 109 | } 110 | 111 | static IEnumerable GetImplementedHandlerInterfaces(Type handlerType) => handlerType.GetInterfaces().Where(IsRebusHandler); 112 | 113 | static bool IsRebusHandler(Type i) => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandleMessages<>); 114 | } -------------------------------------------------------------------------------- /Rebus.Autofac/Config/ContainerExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Autofac; 3 | 4 | namespace Rebus.Config; 5 | 6 | /// 7 | /// Extensions for making it easier to work with Rebus 8 | /// 9 | public static class ContainerExtensions 10 | { 11 | /// 12 | /// When Rebus is registered withg startBus: false, the bus can be started by calling the extension method 13 | /// 14 | public static void StartBus(this IContainer container) 15 | { 16 | if (container == null) throw new ArgumentNullException(nameof(container)); 17 | 18 | container.Resolve().Start(); 19 | } 20 | } -------------------------------------------------------------------------------- /Rebus.Autofac/Internals/InternalsVisibleTo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Rebus.Autofac.Tests")] -------------------------------------------------------------------------------- /Rebus.Autofac/Internals/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Rebus.Internals; 6 | 7 | static class TypeExtensions 8 | { 9 | public static bool IsAssignableTo(this Type sourceType, Type targetType) 10 | { 11 | if (sourceType == null) throw new ArgumentNullException(nameof(sourceType)); 12 | if (targetType == null) throw new ArgumentNullException(nameof(targetType)); 13 | 14 | if (targetType.IsAssignableFrom(sourceType)) 15 | return true; 16 | 17 | foreach (var baseType in sourceType.GetBaseTypes()) 18 | { 19 | if (targetType.IsAssignableFrom(baseType)) 20 | return true; 21 | 22 | if (baseType.IsGenericType && targetType.IsGenericTypeDefinition && 23 | baseType.GetGenericTypeDefinition() == targetType) 24 | return true; 25 | } 26 | 27 | return false; 28 | } 29 | 30 | public static IEnumerable GetBaseTypes(this Type type, bool includeSelf = true, bool includeInterfaces = true) 31 | { 32 | if (type == null) throw new ArgumentNullException(nameof(type)); 33 | 34 | if (includeSelf) 35 | yield return type; 36 | 37 | for (var currentType = type.BaseType; currentType != null; currentType = currentType.BaseType) 38 | { 39 | yield return currentType; 40 | } 41 | 42 | if (includeInterfaces) 43 | { 44 | foreach (var implementedInterface in type.GetInterfaces()) 45 | yield return implementedInterface; 46 | } 47 | } 48 | 49 | public static IReadOnlyList GetGenericTypeParameters(this Type genericType, 50 | Type genericTypeDefinition) 51 | { 52 | if (genericType == null) throw new ArgumentNullException(nameof(genericType)); 53 | if (genericTypeDefinition == null) throw new ArgumentNullException(nameof(genericTypeDefinition)); 54 | 55 | if (!genericTypeDefinition.IsGenericTypeDefinition) 56 | { 57 | var message = $"{genericTypeDefinition} is not a generic type definition."; 58 | throw new ArgumentException(message, nameof(genericTypeDefinition)); 59 | } 60 | 61 | var results = new List(); 62 | 63 | foreach (var baseType in genericType.GetBaseTypes()) 64 | { 65 | if (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == genericTypeDefinition) 66 | results.Add(baseType); 67 | } 68 | 69 | if (results.Count == 0) 70 | { 71 | var message = $"{genericType} does not implement {genericTypeDefinition}."; 72 | throw new ArgumentException(message, nameof(genericType)); 73 | } 74 | 75 | if (results.Count >= 2) 76 | { 77 | var message = new StringBuilder(); 78 | message.AppendLine($"{genericType} implements {genericTypeDefinition} multiple times:"); 79 | 80 | foreach (var result in results) 81 | message.AppendLine($" - {result}"); 82 | 83 | throw new ArgumentException(message.ToString().Trim(), nameof(genericType)); 84 | } 85 | 86 | return results[0].GetGenericArguments(); 87 | } 88 | } -------------------------------------------------------------------------------- /Rebus.Autofac/Rebus.Autofac.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Rebus 4 | Rebus.Autofac 5 | netstandard2.0 6 | 10 7 | mookid8000 8 | https://rebus.fm/what-is-rebus/ 9 | Copyright Rebus FM ApS 2012 10 | rebus autofac ioc dependency-injection 11 | Provides an Autofac container adapter for Rebus 12 | https://github.com/rebus-org/Rebus 13 | git 14 | MIT 15 | little_rebusbus2_copy-500x500.png 16 | README.md 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | True 25 | 26 | 27 | 28 | True 29 | \ 30 | 31 | 32 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2022 2 | 3 | shallow_clone: true 4 | 5 | cache: 6 | - packages -> **\packages.config 7 | - '%LocalAppData%\NuGet\Cache' 8 | 9 | before_build: 10 | - appveyor-retry dotnet restore -v Minimal 11 | 12 | build_script: 13 | - dotnet build Rebus.Autofac -c Release --no-restore 14 | 15 | test_script: 16 | - dotnet test Rebus.Autofac.Tests -c Release --no-restore 17 | -------------------------------------------------------------------------------- /artwork/little_rebusbus2_copy-500x500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebus-org/Rebus.Autofac/d9a01f0bd76f688b5b76618b352c723e81ef86e5/artwork/little_rebusbus2_copy-500x500.png -------------------------------------------------------------------------------- /scripts/build.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set scriptsdir=%~dp0 4 | set root=%scriptsdir%\.. 5 | set project=%1 6 | set version=%2 7 | 8 | if "%project%"=="" ( 9 | echo Please invoke the build script with a project name as its first argument. 10 | echo. 11 | goto exit_fail 12 | ) 13 | 14 | if "%version%"=="" ( 15 | echo Please invoke the build script with a version as its second argument. 16 | echo. 17 | goto exit_fail 18 | ) 19 | 20 | set Version=%version% 21 | 22 | pushd %root% 23 | 24 | dotnet restore --interactive 25 | if %ERRORLEVEL% neq 0 ( 26 | popd 27 | goto exit_fail 28 | ) 29 | 30 | dotnet build "%root%\%project%" -c Release --no-restore 31 | if %ERRORLEVEL% neq 0 ( 32 | popd 33 | goto exit_fail 34 | ) 35 | 36 | popd 37 | 38 | 39 | 40 | 41 | 42 | 43 | goto exit_success 44 | :exit_fail 45 | exit /b 1 46 | :exit_success -------------------------------------------------------------------------------- /scripts/push.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set version=%1 4 | 5 | if "%version%"=="" ( 6 | echo Please remember to specify which version to push as an argument. 7 | goto exit_fail 8 | ) 9 | 10 | set reporoot=%~dp0\.. 11 | set destination=%reporoot%\deploy 12 | 13 | if not exist "%destination%" ( 14 | echo Could not find %destination% 15 | echo. 16 | echo Did you remember to build the packages before running this script? 17 | ) 18 | 19 | set nuget=%reporoot%\tools\NuGet\NuGet.exe 20 | 21 | if not exist "%nuget%" ( 22 | echo Could not find NuGet here: 23 | echo. 24 | echo "%nuget%" 25 | echo. 26 | goto exit_fail 27 | ) 28 | 29 | 30 | "%nuget%" push "%destination%\*.%version%.nupkg" -Source https://nuget.org 31 | if %ERRORLEVEL% neq 0 ( 32 | echo NuGet push failed. 33 | goto exit_fail 34 | ) 35 | 36 | 37 | 38 | 39 | 40 | 41 | goto exit_success 42 | :exit_fail 43 | exit /b 1 44 | :exit_success 45 | -------------------------------------------------------------------------------- /scripts/release.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set scriptsdir=%~dp0 4 | set root=%scriptsdir%\.. 5 | set deploydir=%root%\deploy 6 | set project=%1 7 | set version=%2 8 | 9 | if "%project%"=="" ( 10 | echo Please invoke the build script with a project name as its first argument. 11 | echo. 12 | goto exit_fail 13 | ) 14 | 15 | if "%version%"=="" ( 16 | echo Please invoke the build script with a version as its second argument. 17 | echo. 18 | goto exit_fail 19 | ) 20 | 21 | set Version=%version% 22 | 23 | if exist "%deploydir%" ( 24 | rd "%deploydir%" /s/q 25 | ) 26 | 27 | pushd %root% 28 | 29 | dotnet restore --interactive 30 | if %ERRORLEVEL% neq 0 ( 31 | popd 32 | goto exit_fail 33 | ) 34 | 35 | dotnet pack "%root%/%project%" -c Release -o "%deploydir%" -p:PackageVersion=%version% --no-restore 36 | if %ERRORLEVEL% neq 0 ( 37 | popd 38 | goto exit_fail 39 | ) 40 | 41 | call scripts\push.cmd "%version%" 42 | 43 | popd 44 | 45 | 46 | 47 | 48 | 49 | 50 | goto exit_success 51 | :exit_fail 52 | exit /b 1 53 | :exit_success -------------------------------------------------------------------------------- /tools/NuGet/nuget.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rebus-org/Rebus.Autofac/d9a01f0bd76f688b5b76618b352c723e81ef86e5/tools/NuGet/nuget.exe --------------------------------------------------------------------------------