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 = "");
}
}


