StructureMap API to replace registration from registry
StructureMap allows you to replace an already registered type mapping by clearing all previous registrations for the type and adding new one.
The example in the documentation clears all previous
registration for the type within a registry. What if you want to replace the
registration from the Container
after mapping a type through a Registry
?
One use case for this capability that I ran into recently was while writing a
test case. I wanted to make use of the StructureMap’s Registry
, but replace
one of the type registration with an in-memory implementation. Assumptions
made following the example in the documentation however did not produce the
desired outcome.
Suppose you had the following classes and Registry.
public class InMemoryWidget : IWidget { }
public class Widget : IWidget { }
public class WidgetRegistry : Registry
{
public WidgetRegistry()
{
For<IWidget>().Use<Widget>();
}
}
Notice the difference in the registry compared to the example from StructureMap documentation.
Now, to replace the IWidget
registration to use InMemoryWidget
in the test,
you might assume the following code to do the job.
var container = new Container(cfg =>
{
cfg.AddRegistry<WidgetRegistry>();
cfg.For<IWidget>().ClearAll().Use<InMemoryWidget>();
});
This doesn’t work as expected. If we printed out what the container
contains using WhatDoIHave()
, you will still see 2 registrations.
TestContext.Out.WriteLine(container.WhatDoIHave(pluginType: typeof(IWidget)));
Outputs…
================================================================================
PluginType Namespace Lifecycle Description Name
--------------------------------------------------------------------------------
IWidget Example Transient Example.Widget (Default)
Transient Example.InMemoryWidget
================================================================================
Notice how the first one (Widget
) is the default. Because, it was added first.
The one mapped after clearing all previous registration for IWidget
from our
test is appended to the list of registrations.
The reason for this I gathered is, because the previous registration was done
via a Registry
. And clearing registrations for all types of IWidget
ignores
the ones added via Registry
. The previous approach will only clear registrations
applied directly to the Container
.
In order to clear the registration from the registry in this situation…
var container = new Container(cfg =>
{
var registry = new WidgetRegistry();
registry.For<IWidget>().ClearAll().Use<InMemoryWidget>();
cfg.AddRegistry(registry);
});
You clear the registration from the instance of the registry and pass the
instance to the container configuration’s AddRegistry()
method. We make use of
the AddRegistry
overload that accepts an object instead of the type.
- At time of writing, I am using StructureMap version 4.7.1.