Comparing .Net IoC containers, part four: StructureMap
this test was my first use of StructureMap but I know that it was written by Jeremy D. Miller with help from other contributors. The Apache-licenced source is on Github. It's a fairly modern-looking design, using lambdas. In fact, I could criticise it for requiring lambdas and thus more typing where other IoC containers do not require them. But the point of the single method that does all registration is that it is atomic - it prevents the container being used when registration is half-completed.
Here is basic structureMap usage:
ObjectFactory.Initialize( x => x.For<IJellybeanDispenser>() .Use<VanillaJellybeanDispenser>()); SweetShop sweetShop = ObjectFactory.GetInstance<SweetShop>();
If you don't like the the global ObjectFactory singleton in structuremap, then you can use a container instance instead, like this:
IContainer container = new Container(registry =>
registry.For<IJellybeanDispenser>()
.Use<VanillaJellybeanDispenser>());
SweetShop sweetShop = container.GetInstance<SweetShop>();
Note that with the container, as with calling ObjectFactory.Initialize, the complete configuration is set up in one step, and the container's set of types is immutable afterwards.
With the ObjectFactory singleton, each atomic call to Initialize wipes out the registrations from previous calls. You can use the Configure() method to add to the registrations.
Like Unity, types with discoverable constructors do not need to be registered, so basic usage is still only a couple of lines of code. Objects are not singleton by default. A singleton is made with
ObjectFactory.Initialize( x => x.ForSingletonOf<IJellybeanDispenser>() .Use<VanillaJellybeanDispenser>());
Using an object instance or an object factory is simplicity itself. The Use() method is overloaded:
object instance:
ObjectFactory.Initialize( x => x.For<IJellybeanDispenser>() .Use(new AnyJellybeanDispenser(Jellybean.Cocoa)));
Object factory:
ObjectFactory.Initialize( x => x.For<IJellybeanDispenser>() .Use(c => new AnyJellybeanDispenser(Jellybean.Orange));
I have also written about autoregistration in StructureMap.
StructureMap: The Code
The code is maintianed in a repository here on Github. Here's the complete code for the tests:
namespace IoCComparison
{
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using StructureMap;
[TestFixture]
public class StructureMapTest
{
[Test]
public void CanMakeSweetShopWithVanillaJellybeans()
{
ObjectFactory.Initialize(
x => x.For<IJellybeanDispenser>().Use<VanillaJellybeanDispenser>());
SweetShop sweetShop = ObjectFactory.GetInstance<SweetShop>();
Assert.AreEqual(Jellybean.Vanilla, sweetShop.DispenseJellyBean());
}
[Test]
public void CanMakeSweetShopWithVanillaJellybeansWithContainer()
{
IContainer container = new Container(registry =>
registry.For<IJellybeanDispenser>().Use<VanillaJellybeanDispenser>());
SweetShop sweetShop = container.GetInstance<SweetShop>();
Assert.AreEqual(Jellybean.Vanilla, sweetShop.DispenseJellyBean());
}
[Test]
public void CanMakeSweetShopWithStrawberryJellybeans()
{
ObjectFactory.Initialize(
x => x.For<IJellybeanDispenser>().Use<StrawberryJellybeanDispenser>());
SweetShop sweetShop = ObjectFactory.GetInstance<SweetShop>();
Assert.AreEqual(Jellybean.Strawberry, sweetShop.DispenseJellyBean());
}
[Test]
public void JellybeanDispenserHasNewInstanceEachTime()
{
ObjectFactory.Initialize(
x => x.For<IJellybeanDispenser>().Use<VanillaJellybeanDispenser>());
SweetShop sweetShop = ObjectFactory.GetInstance<SweetShop>();
SweetShop sweetShop2 = ObjectFactory.GetInstance<SweetShop>();
Assert.IsFalse(ReferenceEquals(sweetShop, sweetShop2), "Root objects are equal");
Assert.IsFalse(ReferenceEquals(sweetShop.SweetVendingMachine, sweetShop2.SweetVendingMachine), "Contained objects are equal");
Assert.IsFalse(ReferenceEquals(sweetShop.SweetVendingMachine.JellybeanDispenser, sweetShop2.SweetVendingMachine.JellybeanDispenser), "services are equal");
}
[Test]
public void CanMakeSingletonJellybeanDispenser()
{
ObjectFactory.Initialize(
x => x.ForSingletonOf<IJellybeanDispenser>().Use<VanillaJellybeanDispenser>());
SweetShop sweetShop = ObjectFactory.GetInstance<SweetShop>();
SweetShop sweetShop2 = ObjectFactory.GetInstance<SweetShop>();
Assert.IsFalse(ReferenceEquals(sweetShop, sweetShop2), "Root objects are equal");
Assert.IsFalse(ReferenceEquals(sweetShop.SweetVendingMachine, sweetShop2.SweetVendingMachine), "Contained objects are equal");
// should be same service
Assert.IsTrue(ReferenceEquals(sweetShop.SweetVendingMachine.JellybeanDispenser, sweetShop2.SweetVendingMachine.JellybeanDispenser), "services are not equal");
}
[Test]
public void CanMakeAniseedRootObject()
{
ObjectFactory.Initialize(
x => x.For<SweetShop>().Use<AniseedSweetShop>());
SweetShop sweetShop = ObjectFactory.GetInstance<SweetShop>();
Assert.AreEqual(Jellybean.Aniseed, sweetShop.DispenseJellyBean());
}
[Test]
public void CanUseAnyJellybeanDispenser()
{
ObjectFactory.Initialize(
x => x.For<IJellybeanDispenser>().Use<AnyJellybeanDispenser>()
.Ctor<Jellybean>("jellybean").Is(Jellybean.Lemon));
SweetShop sweetShop = ObjectFactory.GetInstance<SweetShop>();
Assert.AreEqual(Jellybean.Lemon, sweetShop.DispenseJellyBean());
}
[Test]
public void CanUseConstructedObject()
{
ObjectFactory.Initialize(
x => x.For<IJellybeanDispenser>().Use(new AnyJellybeanDispenser(Jellybean.Cocoa)));
SweetShop sweetShop = ObjectFactory.GetInstance<SweetShop>();
Assert.AreEqual(Jellybean.Cocoa, sweetShop.DispenseJellyBean());
}
[Test]
public void CanUseObjectFactory()
{
ObjectFactory.Initialize(
x => x.For<IJellybeanDispenser>().Use(c => new AnyJellybeanDispenser(Jellybean.Orange)));
SweetShop sweetShop = ObjectFactory.GetInstance<SweetShop>();
Assert.AreEqual(Jellybean.Orange, sweetShop.DispenseJellyBean());
}
[Test]
public void CanRegisterMultipleDispensers()
{
ObjectFactory.Initialize(x =>
{
x.For<IJellybeanDispenser>().Use<VanillaJellybeanDispenser>();
x.For<IJellybeanDispenser>().Use<StrawberryJellybeanDispenser>();
});
IEnumerable<IJellybeanDispenser> dispensers = ObjectFactory.GetAllInstances<IJellybeanDispenser>();
Assert.IsNotNull(dispensers);
Assert.AreEqual(2, dispensers.Count());
}
}
}