I was using poor-man’s injection in NServiceBus until this morning I figured out how to handle dependency in NServiceBus. It’s easy, but I never got chance or brave enough to try it out
NServiceBus uses SpringBuilder as default. I want to stick with StructureMap.
Here is official doc for how to wire StructureMap up with NServiceBus: http://sourceforge.net/apps/mediawiki/nservicebus/index.php?title=Additional_containers
// Default // public class EndpointConfig : IConfigureThisEndpoint, AsA_Server // { // } public class EndpointConfigUsingStructuremap : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization { #region IWantCustomInitialization Members public void Init() { Configure.With() .StructureMapBuilder(new Container(new DependencyRegistry())) .XmlSerializer(); // you can leave the rest of the config off since "AsA_Server" handles it } #endregion } public class DependencyRegistry : Registry { public DependencyRegistry() { // Manually set // For<IFileService>().Use<FileService>(); // Or auto scan Scan(x => { x.TheCallingAssembly(); x.AssemblyContainingType<IFileService>(); x.WithDefaultConventions(); }); } } public class DbChangeHandler : IMessageHandler<DatabaseChangedCommand> { private readonly IFileService _fileService; public DbChangeHandler(IFileService fileService) { _fileService = fileService; } public void Handle(DatabaseChangedCommand message) { ... // My old syntax, poor-man/static injection. // FileService.TouchFile(message.DatabaseName, path); _fileService.TouchFile(message.DatabaseName, path); } }
Amazing!
Another team from our company is using Ninject which is not in the out-of-box container list supported by NServiceBus (yet) , google found a solution by Aaron Jenson, https://github.com/aaronjensen/nservicebus.objectbuilder.ninject I will get there soon.
Updated on Mar. 11, 2011:
This code from https://gist.github.com/326321 works in Ninject 2.2 and NServiceBus 2.
public class EndpointConfig : IConfigureThisEndpoint, AsA_Server, IWantCustomInitialization { #region IWantCustomInitialization Members public void Init() { Configure.With() .Log4Net<ConsoleAppender>(x => { x.Threshold = Level.Info; } ).Log4Net<FileAppender>(x => { x.File = "build_trigger_log.txt"; x.Threshold = Level.Info; } ) .NinjectBuilder() .XmlSerializer(); // you can leave the rest of the config off since "AsA_Server" handles it } #endregion } internal class CustomModule : NinjectModule { public override void Load() { Bind<IFileService>().To<FileService>(); } } // NinjectObjectBuilder is from https://gist.github.com/326321 public static class ConfigureNinjectBuilder { public static Configure NinjectBuilder(this Configure config) { ConfigureCommon.With(config, new NinjectObjectBuilder(new StandardKernel(new CustomModule()))); return config; } }
Note:
- If using NServiceBus Testing framework, constructor inject might not work, should use setter inject instead.
- When using autobinding in Ninject, there is a conflict in IMessageSerliazer class, my quick workaround is providing the sample type instead of ScanAssemblyMatch(‘*”), or use Scan WithoutNamespaceOf(“NServiceBus”) to allow NSB use it’s own autobinding on Msmq stuff.
- NSB supports both ctor injection and setter injection, but NSB.Testing framework need a default no-arg ctor, so setter injection is the only choice if using NSB.Testing.
[TestFixture] public class DbChangeHandlerTest { [SetUp] public void Setup() { mockFileService = MockRepository.GenerateMock<IFileService>(); Test.Initialize(); systemUnderTest = Test.Handler<DbChangeHandler>() .WithExternalDependencies(h => h.file_service = mockFileService); } IFileService mockFileService; Handler<DbChangeHandler> systemUnderTest; [Test] public void should_call_file_service_to_touch_file() { systemUnderTest .OnMessage<DatabaseChangedCommand>(m => m.DatabaseName = ""); mockFileService.AssertWasCalled(x => x.TouchFile("", ""), opt => opt.IgnoreArguments()); } [Test] public void should_response_to_database_changed_command() { systemUnderTest .OnMessage<DatabaseChangedCommand>(m => m.DatabaseName = ""); } [Test] public void should_return_error_code_zero() { systemUnderTest .ExpectReturn(errCode => errCode == 0) .OnMessage<DatabaseChangedCommand>(m => m.DatabaseName = ""); } }