TODO(Write content!)
- - -diff --git a/architecture/index.html b/architecture/index.html deleted file mode 100644 index 2c93936..0000000 --- a/architecture/index.html +++ /dev/null @@ -1,130 +0,0 @@ - - -
- - - - -TODO(Write content!)
- - -When you need to implement Abstract Factory, StructureMap offers a way to do it for you. Let's say you have
+
public interface IDummyService
{
string Name { get; }
}
+with implementation
+
public class DummyService : IDummyService
{
public string Name { get; set; }
}
+Now you declare an interface for your factory:
+
public interface ISimpleDummyFactory
{
IDummyService CreateDummyService();
}
+All you need to do is to call CreateFactory
when configuring the container as shown below:
[Fact]
public void Simple_factory_creation()
{
var container = new Container(cfg =>
{
cfg.For<IDummyService>().Use<DummyService>();
cfg.For<ISimpleDummyFactory>().CreateFactory();
});
var factory = container.GetInstance<ISimpleDummyFactory>();
var component = factory.CreateDummyService();
component.ShouldNotBeNull();
component.ShouldBeOfType<DummyService>();
}
+As for now, Auto-factories support two types of methods:
+To declare a method that has to return the names of registered implementations, the method signature must satisfy the following conditions:
+GetNames
List<string>
e.g. IList<string>
, IEnumerable<string>
Any other method that has the return type (i.e. doesn't return void
), is treated as a factory method. In addition, if the method name starts with GetNamed
, the first method argument is used as the name for the named instance. All the rest arguments are passed as explicit arguments to the implementation constructor.
It is much easier to see it on an example:
+
public interface IDummyFactory
{
// This method will return the names of all registered implementations of TService.
IList<string> GetNames<TService>();
// This method will just create the default IDummyService implementation.
IDummyService CreateDummyService();
// This method will just create the default IDummyService implementation and pass namePart1 and namePart2 as
// dependencies.
IDummyService CreateDummyService(string namePart1, string namePart2);
// This method will create IDummyService implementation with serviceName name.
IDummyService GetNamedDummyService(string serviceName, string namePart1, string namePart2);
// Generic methods are also allowed as factory methods.
TService CreateService<TService>();
// Something that is common for event-sourcing implementations.
IHandler<TMessage> CreateHandler<TMessage>();
}
+If the default convention doesn't work for you, you can create and use your custom convention. All you need is to implement IAutoFactoryConventionProvider
and use the corresponding CreateFactory
overload. IAutoFactoryConventionProvider
has a single method to implement:
IAutoFactoryMethodDefinition GetMethodDefinition(MethodInfo methodInfo, IList<object> arguments);
+
+IAutoFactoryMethodDefinition
is defined as follows:
public interface IAutoFactoryMethodDefinition
{
AutoFactoryMethodType MethodType { get; }
Type InstanceType { get; }
string InstanceName { get; }
ExplicitArguments ExplicitArguments { get; }
}
+
+ All of these recommendations are the opinions and sole responsiblity of one Jeremy D. Miller. The single best advice I can give you +about using StructureMap is to avoid being too clever with your usage.
+In idiomatic StructureMap usage, I strongly recommend using a nested container for short lived operations like:
+To repeat the section above, I strongly recommend using nested containers instead of the legacy ASP.Net lifecycles to scope +services per HTTP request.
+Unfortunately, the Container.Configure()
method is potentially an expensive operation
+and can result in some container-wide locks if you change any kind of interception or construction policy. Avoid this mechanism at runtime. If you need
+to inject services at runtime, try to do those overrides in an isolated nested container for that
+particular request or transaction to avoid hitting any kind of shared lock.
Container.TryGetInstance()
Use the container to resolve your dependency relationships or don't. In my opinion, using TryGetInstance()
results in unnecessary complexity in your application. My recommendation is to use nullo objects as stand-ins or to use "modular registration" strategies instead (See Fallback Services and Replace or Clear Out Previous Registrations for more information). The ASP.Net team requires this usage for all of their IoC container integrations and you can't fight city hall, so StructureMap 4.0 includes some performance optimizations specifically for the heavy TryGetInstance()
usage that I never anticipated.
I believe that constructor injection is less error prone than setter injection and is more easily traceable later. Setter injection is occasionally easier +to use (in inheritance relationships for an example), but is mostly available in StructureMap as a workaround for code that was not built with dependency +injection in mind (or popular frameworks that were built around Spring.Net usage cough NServiceBus cough).
+See Profiles and Child Containers for more information.
+While you can completely set up a Container
object through its constructor function and repeated calls to Container.Configure()
, we suggest that you
+express any configurations in Registry objects for repeatable configuration later in tests and for a cleaner expression
+of the configuration.
Do consider breaking your configuration across separate Registry
objects for different subsystems if the StructureMap configuration gets complicated.
If your choice is between making a direct dependency from one assembly to another strictly to make the StructureMap configuration easy and less error prone or using dynamic assembly loading and configuration strategies with type scanning to comply with the Onion Architecture, I very strongly recommend you favor the less error prone, direct assembly dependencies.
+While there are many powerful things you can do with StructureMap at runtime for conditional object resolution with lambdas and IContext, +I recommend trying to "bake in" building decisions upfront with build policies for more efficient object resolution and so that +the container behavior is surfaced through diagnostics like the build plan visualization.
+ +TODO(Write some content!)
- + -StructureMap 3.0 introduced the concept of the "Build Plan." The build plan is a textual representation of exactly how StructureMap will build a given Instance, including:
+Func<T>
that is used to construct the Instance objectTo retrieve the build plan for a configured Instance, use the queryable Container.Model
to find the configured Instance and call DescribeBuildPlan(int maxDepth)
to get the textual report as shown in this sample below:
var container = Container.For<VisualizationRegistry>();
var description = container.Model.For<IDevice>().Default
.DescribeBuildPlan();
Debug.WriteLine(description);
+The result of the code above is this textual representation of how StructureMap will build and/or resolve the default of the IDevice
plugin type:
+PluginType: StructureMap.Testing.Diagnostics.IDevice +Lifecycle: Transient +Decorator --> FuncInterceptor of StructureMap.Testing.Diagnostics.IDevice: new DeviceDecorator(IDevice) +Decorator --> Decorator of type StructureMap.Testing.Diagnostics.CrazyDecorator + new CrazyDecorator(IDevice, IEngine, IFoo) + ┣ IDevice = The inner IDevice + ┃ ┗ new DefaultDevice() + ┣ IEngine = **Default** + ┗ IFoo = **Default** + ++
For another example, you can retrieve the build plan for a named instance of a certain build plan with this code:
+
var description = theContainer.Model.For<IDevice>()
.Find("A")
.DescribeBuildPlan();
+See Using the Container Model for more information on using Container.Model
.
You can find many more examples of finding the build plan description from Container.Model
from the unit tests in the StructureMap codebase.
TODO(Write some content!)
- + -Years ago I worked with a legacy system that was particularly fragile in its deployment. While my team at the time and I made some serious improvements in the reliability of the automated deployment, the best thing we did was to add a set of environment tests to the deployment that verified that basic elements of the system were working like:
+The deployments still frequently failed, but we were able to spot and diagnose the underlying problems much faster with our new environment tests than we could before by trying to run and debug the not-quite-valid application.
+One of the mechanisms we used for these environment tests was StructureMap's ability to mark methods on configured types as environment tests with the [ValidationMethod]
attribute as shown below:
public class Database : IDatabase
{
[ValidationMethod]
public void TryToConnect()
{
// try to open a connection to the configured
// database connection string
// throw an exception if the database cannot
// be reached
}
}
+Used in conjunction with StructureMap's ability to validate a container, you can use this technique to quickly support environment tests embedded into your system code.
+ +TODO(Write some content!)
- + -Type scanning and conventional auto-registration is a very powerful feature in StructureMap, but it has been frequently troublesome to users when things go wrong. To try to alleviate problems, StructureMap 4.0 introduces some new functionality for detecting and diagnosing problems with type scanning, mostly related to Assembly's being missing.
+At its root, most type scanning and auto-registration schemes in .Net frameworks rely on the Assembly.GetExportedTypes() method. Unfortunately, that method can be brittle and fail whenever any dependency of that Assembly cannot be loaded into the current process, even if your application has no need for that dependency. In StructureMap 3.* and before, that loading exception was essentially swallowed and lost. In StructureMap 4 and above, you can use this method to assert the presence of any assembly load exceptions during type scanning:
+
TypeRepository.AssertNoTypeScanningFailures();
+The method above will throw an exception listing all the Assembly's that failed during the call to GetExportedTypes()
only if there were any failures. Use this method during your application bootstrapping if you want it to fail fast with any type scanning problems.
Confusion of type scanning has been a constant problem with StructureMap usage over the years -- especially if users are trying to dynamically load assemblies from the file system for extensibility. In order to see into what StructureMap has done with type scanning, 4.0 introduces the Container.WhatDidIScan()
method.
Let's say that you have a Container
that is set up with at least two different scanning operations like this sample from the StructureMap unit tests:
var container = new Container(_ =>
{
_.Scan(x =>
{
x.TheCallingAssembly();
x.WithDefaultConventions();
x.RegisterConcreteTypesAgainstTheFirstInterface();
x.SingleImplementationsOfInterface();
});
_.Scan(x =>
{
// Give your scanning operation a descriptive name
// to help the diagnostics to be more useful
x.Description = "Second Scanner";
x.AssembliesFromApplicationBaseDirectory(assem => assem.FullName.Contains("Widget"));
x.ConnectImplementationsToTypesClosing(typeof(IService<>));
x.AddAllTypesOf<IWidget>();
});
});
Debug.WriteLine(container.WhatDidIScan());
+The resulting textual report is shown below:
+Sorry for the formatting and color of the text, but the markdown engine does not like the textual report
+
/*
All Scanners
================================================================
Scanner #1
Assemblies
----------
* StructureMap.Testing, Version=4.0.0.51243, Culture=neutral, PublicKeyToken=null
Conventions
--------
* Default I[Name]/[Name] registration convention
* Register all concrete types against the first interface (if any) that they implement
* Register any single implementation of any interface against that interface
Second Scanner
Assemblies
----------
* StructureMap.Testing.GenericWidgets, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
* StructureMap.Testing.Widget, Version=4.0.0.51243, Culture=neutral, PublicKeyToken=null
* StructureMap.Testing.Widget2, Version=4.0.0.51243, Culture=neutral, PublicKeyToken=null
* StructureMap.Testing.Widget3, Version=4.0.0.51243, Culture=neutral, PublicKeyToken=null
* StructureMap.Testing.Widget4, Version=4.0.0.51243, Culture=neutral, PublicKeyToken=null
* StructureMap.Testing.Widget5, Version=4.0.0.51243, Culture=neutral, PublicKeyToken=null
Conventions
--------
* Connect all implementations of open generic type IService<T>
* Find and register all types implementing StructureMap.Testing.Widget.IWidget
*/
+The textual report will show:
+Registry.Scan()
) with a descriptive name, either one supplied by you or the Registry
type and an order number.Assembly.GetExportedTypes()
failed on that assembly.WhatDidIScan()
does not at this time show any type filters or exclusions that may be part of the assembly scanner.
See also: Auto-Registration and Conventions
+ +The queryable Container.Model
is a power facility to look into your StructureMap Container
and even to eject previously built services from the Container. The Container.Model
represents a static view of what a Container
already has, and does not account for policies that may allow StructureMap to validly discover types that it may encounter later at runtime.
The WhatDoIHave() mechanism works by just iterating over the Container.Model.PluginTypes
collection as shown below:
container.Model.PluginTypes.Where(x => x.PluginType.Assembly == Assembly.GetExecutingAssembly())
.Each(pluginType => Debug.WriteLine(pluginType.PluginType));
+The IPluginTypeConfiguration
interface allows you to query and manipulate all the configured Instance's for a given plugin type.
See the entire IPluginTypeConfiguration interface here.
+To simply find out what the default concrete type would be for a requested plugin type, use one of these two methods:
+
// Finding the concrete type of the default
// IDevice service
container.Model.DefaultTypeFor<IDevice>()
.ShouldBe(typeof(DefaultDevice));
// Find the configuration model for the default
// IDevice service
container.Model.For<IDevice>().Default
.ReturnedType.ShouldBe(typeof(DefaultDevice));
+Use this syntax to find information about an Instance in a given plugin type and name:
+
var redRule = container.Model.Find<Rule>("Red");
+This sample shows how you could iterate or query over all the registered instances for a single plugin type:
+
container.Model.For<Rule>().Instances.Each(i =>
{
Debug.WriteLine(i.Instance.Description);
});
+It's possible to remove singleton scoped objects from a running Container to force a new one to be built or even to completely remove configured instance objects and configuration permanently from a Container. This is typically only used in automated testing to flush static state between tests.
+To remove and dispose previously built singleton scoped objects from a Container, use this code:
+
// ONLY ejects any built object for this Instance from the SingletonThing
// cache
container.Model.For<IDevice>().Default.EjectObject();
+To completely eject any singletons and permanently remove all related configuration, use this code:
+
// Removes all configurations and objects already built as singletons
// related to types in the current Assembly
container.Model.EjectAndRemoveTypes(type => type.Assembly == Assembly.GetExecutingAssembly());
// Removes all configurations and objects already built as singletons
// that were registered to IDevice
container.Model.EjectAndRemove(typeof(IDevice));
+To troubleshoot or automate testing of Container configuration, you can use code like the sample below to +test for the presence of expected configurations:
+
// Is there a default instance for IDevice?
container.Model.HasDefaultImplementationFor<IDevice>().ShouldBeTrue();
// Are there any configured instances for IDevice?
container.Model.HasImplementationsFor<IDevice>().ShouldBeTrue();
+Forget about what types are registered for whatever plugin types and consider this, what if you have an interface called
+IStartable
that just denotes objects that will need to be activated after the container is bootstrapped?
If our interface is this below:
+
public interface IStartable
{
bool WasStarted { get; }
void Start();
}
+We could walk through the entire StructureMap model and find every registered instance that implements this interface, create each, and call the Start()
method like in this code below:
var allStartables = container.Model.GetAllPossible<IStartable>();
allStartables.ToArray()
.Each(x => x.Start());
+I've also used this mechanism in automated testing to reach out to all singleton services that may have state to clear out their data between tests.
+You can manipulate an individual instance in several ways:
+
// First, find the model for a single Instance
var instance = container.Model.For<IDevice>().Default;
// build or resolve an object for this Instance cast to
// the type specified to the Get() method
instance.Get<IDevice>().ShouldBeOfType<DefaultDevice>();
// if the instance is configured as a SingletonThing, test
// if the SingletonThing object has already been created
var hasSingletonBeenCreated = instance.ObjectHasBeenCreated();
if (hasSingletonBeenCreated)
{
// remove the SingletonThing object from the cache so that
// StructureMap will be forced to rebuild this object
instance.EjectObject();
}
// test the lifecycle of this instance
instance.Lifecycle.ShouldBeOfType<SingletonLifecycle>();
// Visualize the build plan no more than 3 levels deep
Debug.WriteLine(instance.DescribeBuildPlan(3));
// Get at the underlying Instance model that StructureMap itself
// uses. Be cautious using this.
var rawModel = instance.Instance;
+
+ TODO(Write some content!)
- + -To find any potential holes in your StructureMap configuration like missing dependencies, unclear defaults of plugin types, validation errors, or just plain build errors, you can use this method below:
+
container.AssertConfigurationIsValid();
+Running this method will walk over every single registration in your Container
and:
[ValidationMethod]
attribute to perform environment tests. See Environment Tests for more information on this usage.If StructureMap encounters any errors of any kind during this method, it will throw an exception summarizing all of the problems that it encountered. That output will look something like:
++ + StructureMap.StructureMapConfigurationException + StructureMap Failures: 1 Build/Configuration Failures and 0 Validation Errors + + Profile 'DEFAULT' + + ----------------------------------------------------------------------------------------------------- + Build Error on Instance 'StructureMap.Testing.Diagnostics.NamedWidget' + for PluginType StructureMap.Testing.Diagnostics.IWidget + + Unable to create a build plan for concrete type StructureMap.Testing.Diagnostics.NamedWidget + new NamedWidget(String name) + ┗ String name = Required primitive dependency is not explicitly defined + ++
If you take advantage of StructureMap's ability to supply arguments at runtime, you may need to add fake or stubbed stand in services to StructureMap just to satisfy dependencies while calling Container.AssertConfigurationIsValid()
. For example, in FubuMVC we supply several services representing an HTTP request as explicit arguments. In order to use the container validation, we have to register stand in services in the main container.
TODO(Write some content!)
- + -The IContainer.WhatDoIHave()
method can give you a quick textual report of the current configuration of a running Container
:
- var container = new Container();
- var report = container.WhatDoIHave();
-
- Debug.WriteLine(report);
-
-If you're familiar with WhatDoIHave()
from earlier versions of StructureMap, the usage has been enhanced for 3.0 to allow you
-to filter the results for easier usage. The format was also tweaked extensively to (hopefully) improve the usability of this feature.
Enough talk, say you have a Container
with this configuration:
- var container = new Container(x =>
- {
- x.For<IEngine>().Use<Hemi>().Named("The Hemi");
-
- x.For<IEngine>().Add<VEight>().Singleton().Named("V8");
- x.For<IEngine>().Add<FourFiftyFour>().AlwaysUnique();
- x.For<IEngine>().Add<StraightSix>().LifecycleIs<ThreadLocalStorageLifecycle>();
-
- x.For<IEngine>().Add(() => new Rotary()).Named("Rotary");
- x.For<IEngine>().Add(c => c.GetInstance<PluginElectric>());
-
- x.For<IEngine>().Add(new InlineFour());
-
- x.For<IEngine>().UseIfNone<VTwelve>();
- x.For<IEngine>().MissingNamedInstanceIs.ConstructedBy(c => new NamedEngine(c.RequestedName));
- });
-
-If you were to run the code below against this Container
:
- Debug.WriteLine(container.WhatDoIHave());
-
-you would get the output shown in this gist.
-If you're curious, all the raw code for this example is in here.
-Filtering the WhatDoIHave()
results can be done in these ways:
- var container = new Container();
-
- // Filter by the Assembly of the Plugin Type
- var byAssembly = container.WhatDoIHave(assembly: typeof (IWidget).Assembly);
-
- // Only report on the specified Plugin Type
- var byPluginType = container.WhatDoIHave(typeof (IWidget));
-
- // Filter to Plugin Type's in the named namespace
- // The 'IsInNamespace' test will include child namespaces
- var byNamespace = container.WhatDoIHave(@namespace: "StructureMap.Testing.Widget");
-
- // Filter by a case insensitive string.Contains() match
- // against the Plugin Type name
- var byType = container.WhatDoIHave(typeName: "Widget");
-
-
-
- The IContainer.WhatDoIHave()
method can give you a quick textual report of the current configuration of a running Container
:
var container = new Container();
var report = container.WhatDoIHave();
Debug.WriteLine(report);
+If you're familiar with WhatDoIHave()
from earlier versions of StructureMap, the usage has been enhanced for 3.0 to allow you
+to filter the results for easier usage. The format was also tweaked extensively to (hopefully) improve the usability of this feature.
Enough talk, say you have a Container
with this configuration:
var container = new Container(x =>
{
x.For<IEngine>().Use<Hemi>().Named("The Hemi");
x.For<IEngine>().Add<VEight>().Singleton().Named("V8");
x.For<IEngine>().Add<FourFiftyFour>().AlwaysUnique();
x.For<IEngine>().Add<StraightSix>().LifecycleIs<ThreadLocalStorageLifecycle>();
x.For<IEngine>().Add(() => new Rotary()).Named("Rotary");
x.For<IEngine>().Add(c => c.GetInstance<PluginElectric>());
x.For<IEngine>().Add(new InlineFour());
x.For<IEngine>().UseIfNone<VTwelve>();
x.For<IEngine>().MissingNamedInstanceIs.ConstructedBy(c => new NamedEngine(c.RequestedName));
});
+If you were to run the code below against this Container
:
Debug.WriteLine(container.WhatDoIHave());
+you would get the output shown in this gist.
+If you're curious, all the raw code for this example is in here.
+Filtering the WhatDoIHave()
results can be done in these ways:
var container = new Container();
// Filter by the Assembly of the Plugin Type
var byAssembly = container.WhatDoIHave(assembly: typeof(IWidget).GetAssembly());
// Only report on the specified Plugin Type
var byPluginType = container.WhatDoIHave(typeof(IWidget));
// Filter to Plugin Type's in the named namespace
// The 'IsInNamespace' test will include child namespaces
var byNamespace = container.WhatDoIHave(@namespace: "StructureMap.Testing.Widget");
// Filter by a case insensitive string.Contains() match
// against the Plugin Type name
var byType = container.WhatDoIHave(typeName: "Widget");
+
+ The documentation may never be exhaustive, but here are the major sections so far:
-The documentation may never be exhaustive, but here are the major sections so far:
+The Interception and Decorators page describes how to use "static" interception of created instances, mainly allowing to apply the Decorator pattern. It is "static" in a sense that you need know what interfaces you want to implement and you need to create decorators implementing all appropriate interfaces. It is almost always fine, but there are cases when you want to implement the same decorating logic for many interfaces which easily breaks the DRY principle. The most common examples are cross-cutting concerns such as logging, caching etc.
+Let's see it in action. Let's say we have
+
public interface IMathService
{
int GetSquareRoot(int value);
Task<int> GetSquareRootAsync(int value);
}
+with implementation
+
private class MathService : IMathService
{
public int GetSquareRoot(int value)
{
return (int)Math.Sqrt(value);
}
public async Task<int> GetSquareRootAsync(int value)
{
await Task.Yield();
return (int)Math.Sqrt(value);
}
}
+If you need to apply dynamic interception to IMathService
, first you implement either ISyncInterceptionBehavior
or IAsyncInterceptionBehavior
depending if your interception code needs to use async
/await
or not. For demonstration purposes, let's have
private class NegatingInterceptor : ISyncInterceptionBehavior
{
public IMethodInvocationResult Intercept(ISyncMethodInvocation methodInvocation)
{
var argument = methodInvocation.GetArgument("value");
var argumentValue = (int)argument.Value;
if (argumentValue < 0)
{
argument.Value = -argumentValue;
}
return methodInvocation.InvokeNext();
}
}
+and
+
private class AsyncCachingInterceptor : IAsyncInterceptionBehavior
{
private static readonly IDictionary<int, int> PrecalculatedValues = new Dictionary<int, int>
{
{ 16, 4444 },
{ 10, 5555 },
};
public async Task<IMethodInvocationResult> InterceptAsync(IAsyncMethodInvocation methodInvocation)
{
var argument = methodInvocation.GetArgument("value");
var argumentValue = (int)argument.Value;
int result;
return PrecalculatedValues.TryGetValue(argumentValue, out result)
? methodInvocation.CreateResult(result)
: await methodInvocation.InvokeNextAsync().ConfigureAwait(false);
}
}
+Finally, we register interceptors with help of DynamicProxyInterceptor
as follows:
[Theory]
[InlineData(111, 10)]
[InlineData(16, 4444)]
[InlineData(-16, 4444)]
public void CallSyncMethodWithSyncThenAsyncInterceptors(int value, int expectedResult)
{
var container = new Container(x =>
{
x.For<IMathService>().Use<MathService>()
.InterceptWith(new DynamicProxyInterceptor<IMathService>(new IInterceptionBehavior[]
{
new NegatingInterceptor(),
new AsyncCachingInterceptor()
}));
});
var service = container.GetInstance<IMathService>();
service.GetSquareRoot(value).ShouldBe(expectedResult);
}
+The idea is simple - for each method call of the intercepted instance, Intercept
/InterceptAsync
is called passing an IMethodInvocation
instance allowing to get information about the intercepted method and modify arguments if needed before passing to the next interceptor. You have a choice to call the next interceptor in the chain via methodInvocation.InvokeNext
/methodInvocation.InvokeNextAsync
. Alternatively, you can return the result directly from the interceptor via methodInvocation.CreateResult
.
Finally, you can also throw exceptions from interceptors either directly or by returning methodInvocation.CreateExceptionResult
.
As described on the Interception and Decorators page, you can create an interception policy if you need to apply interceptors to many types by certain filter. DynamicProxyInterceptorPolicy
makes it easier when it comes to dynamic interceptors. See the example below:
[Fact]
public void UseInterceptionPolicy()
{
var container = new Container(x =>
{
x.Policies.Interceptors(new DynamicProxyInterceptorPolicy(new NegatingInterceptor(), new CachingInterceptor()));
x.For<IMathService>().Use<MathService>();
});
var service = container.GetInstance<IMathService>();
service.GetSquareRoot(-10).ShouldBe(5555);
}
+Check DynamicProxyInterceptorPolicy
constructors to find the most suitable overload for your purposes.
TODO(Write some content!)
- - -The following things are features that are not uncommon in other IoC tools or were present in previous versions of StructureMap.
-The following things are features that are not uncommon in other IoC tools or were present in previous versions of StructureMap.
+StructureMap comes with some power abilities to exploit open generic types in .Net for extensibility +and flexible handling within your system.
+I worked years ago on a system that could be used to record and resolve customer support problems. Since it was very workflow heavy in its logic, +we tracked user and system activity as an event stream of small objects that reflected all the different actions or state changes +that could happen to an issue. To render and visualize the activity log to HTML, we used many of the open generic type capabilities shown in +this topic to find and apply the correct HTML rendering strategy for each type of log object in an activity stream.
+Given a log object, we wanted to look up the right visualizer strategy to render that type of log object to html on the server side.
+To start, we had an interface like this one that we were going to use to get the HTML for each log object:
+
public interface ILogVisualizer
{
// If we already know what the type of log we have
string ToHtml<TLog>(TLog log);
// If we only know that we have a log object
string ToHtml(object log);
}
+So for an example, if we already knew that we had an IssueCreated
object, we should be able to use StructureMap like this:
// Just setting up a Container and ILogVisualizer
var container = Container.For<VisualizationRegistry>();
var visualizer = container.GetInstance<ILogVisualizer>();
// If I have an IssueCreated lob object...
var created = new IssueCreated();
// I can get the html representation:
var html = visualizer.ToHtml(created);
+If we had an array of log objects, but we do not already know the specific types, we can still use the more generic ToHtml(object)
method like this:
var logs = new object[]
{
new IssueCreated(),
new TaskAssigned(),
new Comment(),
new IssueResolved()
};
// SAMPLE: using-visualizer-knowning-the-type
// Just setting up a Container and ILogVisualizer
var container = Container.For<VisualizationRegistry>();
var visualizer = container.GetInstance<ILogVisualizer>();
var items = logs.Select(visualizer.ToHtml);
var html = string.Join("<hr />", items);
+The next step is to create a way to identify the visualization strategy for a single type of log object. We certainly could have done this +with a giant switch statement, but we wanted some extensibility for new types of activity log objects and even customer specific log types +that would never, ever be in the main codebase. We settled on an interface like the one shown below that would be responsible for +rendering a particular type of log object ("T" in the type):
+
public interface IVisualizer<TLog>
{
string ToHtml(TLog log);
}
+Inside of the concrete implementation of ILogVisualizer
we need to be able to pull out and use the correct IVisualizer<T>
strategy for a log type. We of course
+used a StructureMap Container
to do the resolution and lookup, so now we also need to be able to register all the log visualization strategies in some easy way.
+On top of that, many of the log types were simple and could just as easily be rendered with a simple html strategy like this class:
public class DefaultVisualizer<TLog> : IVisualizer<TLog>
{
public string ToHtml(TLog log)
{
return string.Format("<div>{0}</div>", log);
}
}
+Inside of our StructureMap usage, if we don't have a specific visualizer for a given log type, we'd just like to fallback to the default visualizer and proceed.
+Alright, now that we have a real world problem, let's proceed to the mechanics of the solution.
+Let's say to begin with all we want to do is to always use the DefaultVisualizer
for each log type. We can do that with code like this below:
[Fact]
public void register_open_generic_type()
{
var container = new Container(_ =>
{
_.For(typeof(IVisualizer<>)).Use(typeof(DefaultVisualizer<>));
});
Debug.WriteLine(container.WhatDoIHave(@namespace: "StructureMap.Testing.Acceptance.Visualization"));
container.GetInstance<IVisualizer<IssueCreated>>()
.ShouldBeOfType<DefaultVisualizer<IssueCreated>>();
Debug.WriteLine(container.WhatDoIHave(@namespace: "StructureMap.Testing.Acceptance.Visualization"));
container.GetInstance<IVisualizer<IssueResolved>>()
.ShouldBeOfType<DefaultVisualizer<IssueResolved>>();
}
+With the configuration above, there are no specific registrations for IVisualizer<IssueCreated>
. At the first request for that
+interface, StructureMap will run through its "missing family policies", one of which is
+to try to find registrations for an open generic type that could be closed to make a valid registration for the requested type. In the case above,
+StructureMap sees that it has registrations for the open generic type IVisualizer<T>
that could be used to create registrations for the
+closed type IVisualizer<IssueCreated>
.
Using the WhatDoIHave() diagnostics, the original state of the container for the visualization namespace is:
++=========================================================================================================================== +PluginType Namespace Lifecycle Description Name +--------------------------------------------------------------------------------------------------------------------------- +IVisualizer<TLog> StructureMap.Testing.Acceptance.Visualization Transient DefaultVisualizer<TLog> (Default) +=========================================================================================================================== ++
After making a request for IVisualizer<IssueCreated>
, the new state is:
+==================================================================================================================================================================================== +PluginType Namespace Lifecycle Description Name +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +IVisualizer<IssueCreated> StructureMap.Testing.Acceptance.Visualization Transient DefaultVisualizer<IssueCreated> ('548b4256-a7aa-46a3-8072-bd8ef0c5c430') (Default) +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +IVisualizer<TLog> StructureMap.Testing.Acceptance.Visualization Transient DefaultVisualizer<TLog> (Default) +==================================================================================================================================================================================== + + ++
A powerful feature of generic type support in StructureMap is the ability to register specific handlers for some types, but allow +users to register a "fallback" registration otherwise. In the case of the visualization, some types of log objects may justify some +special HTML rendering while others can happily be rendered with the default visualization strategy. This behavior is demonstrated by +the following code sample:
+
[Fact]
public void generic_defaults()
{
var container = new Container(_ =>
{
// The default visualizer just like we did above
_.For(typeof(IVisualizer<>)).Use(typeof(DefaultVisualizer<>));
// Register a specific visualizer for IssueCreated
_.For<IVisualizer<IssueCreated>>().Use<IssueCreatedVisualizer>();
});
// We have a specific visualizer for IssueCreated
container.GetInstance<IVisualizer<IssueCreated>>()
.ShouldBeOfType<IssueCreatedVisualizer>();
// We do not have any special visualizer for TaskAssigned,
// so fall back to the DefaultVisualizer<T>
container.GetInstance<IVisualizer<TaskAssigned>>()
.ShouldBeOfType<DefaultVisualizer<TaskAssigned>>();
}
+Registry
classes that explicitly configure services can easily fall into that category. Using type scanning registration can help
+ teams avoid that problem altogether by eliminating the need to make any explict registrations as new providers are added to the codebase.For this example, I have two special visualizers for the IssueCreated
and IssueResolved
log types:
public class IssueCreatedVisualizer : IVisualizer<IssueCreated>
{
public string ToHtml(IssueCreated log)
{
return "special html for an issue being created";
}
}
public class IssueResolvedVisualizer : IVisualizer<IssueResolved>
{
public string ToHtml(IssueResolved log)
{
return "special html for issue resolved";
}
}
+In the real project that inspired this example, we had many, many more types of log visualizer strategies and it
+could have easily been very tedious to manually register all the different little IVisualizer<T>
strategy types in a Registry
class by hand.
+Fortunately, part of StructureMap's type scanning support is the ConnectImplementationsToTypesClosing()
+auto-registration mechanism via generic templates for exactly this kind of scenario.
In the sample below, I've set up a type scanning operation that will register any concrete type in the Assembly that contains the VisualizationRegistry
+that closes IVisualizer<T>
against the proper interface:
public class VisualizationRegistry : Registry
{
public VisualizationRegistry()
{
// The main ILogVisualizer service
For<ILogVisualizer>().Use<LogVisualizer>();
// A default, fallback visualizer
For(typeof(IVisualizer<>)).Use(typeof(DefaultVisualizer<>));
// Auto-register all concrete types that "close"
// IVisualizer<TLog>
Scan(x =>
{
x.TheCallingAssembly();
x.ConnectImplementationsToTypesClosing(typeof(IVisualizer<>));
});
}
}
+If we create a Container
based on the configuration above, we can see that the type scanning operation picks up the specific visualizers for
+IssueCreated
and IssueResolved
as shown in the diagnostic view below:
+================================================================================================================================================================================== +PluginType Namespace Lifecycle Description Name +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +ILogVisualizer StructureMap.Testing.Acceptance.Visualization Transient StructureMap.Testing.Acceptance.Visualization.LogVisualizer (Default) +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IVisualizer<IssueResolved> StructureMap.Testing.Acceptance.Visualization Transient StructureMap.Testing.Acceptance.Visualization.IssueResolvedVisualizer (Default) + Transient DefaultVisualizer<IssueResolved> +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IVisualizer<IssueCreated> StructureMap.Testing.Acceptance.Visualization Transient StructureMap.Testing.Acceptance.Visualization.IssueCreatedVisualizer (Default) + Transient DefaultVisualizer<IssueCreated> +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IVisualizer<TLog> StructureMap.Testing.Acceptance.Visualization Transient DefaultVisualizer<TLog> (Default) +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +IVisualizer<TLog> StructureMap.Testing.Acceptance.Visualization Transient DefaultVisualizer<TLog> (Default) +================================================================================================================================================================================== + ++
The following sample shows the VisualizationRegistry
in action to combine the type scanning registration plus the default fallback behavior for
+log types that do not have any special visualization logic:
[Fact]
public void visualization_registry()
{
var container = Container.For<VisualizationRegistry>();
Debug.WriteLine(container.WhatDoIHave(@namespace: "StructureMap.Testing.Acceptance.Visualization"));
container.GetInstance<IVisualizer<IssueCreated>>()
.ShouldBeOfType<IssueCreatedVisualizer>();
container.GetInstance<IVisualizer<IssueResolved>>()
.ShouldBeOfType<IssueResolvedVisualizer>();
// We have no special registration for TaskAssigned,
// so fallback to the default visualizer
container.GetInstance<IVisualizer<TaskAssigned>>()
.ShouldBeOfType<DefaultVisualizer<TaskAssigned>>();
}
+Working with generic types and the common IHandler<T>
pattern can be a little bit tricky if all you have is an object that is declared as an object
. Fortunately,
+StructureMap has a couple helper methods and mechanisms to help you bridge the gap between DoSomething(object something)
and DoSomething<T>(T something)
.
If you remember the full ILogVisualizer
interface from above:
public interface ILogVisualizer
{
// If we already know what the type of log we have
string ToHtml<TLog>(TLog log);
// If we only know that we have a log object
string ToHtml(object log);
}
+The method ToHtml(object log)
somehow needs to be able to find the right IVisualizer<T>
and execute it to get the HTML representation for a log object.
+The StructureMap IContainer
provides two different methods called ForObject()
and ForGenericType()
for exactly this case, as shown below in a possible implementation
+of ILogVisualizer
:
public class LogVisualizer : ILogVisualizer
{
private readonly IContainer _container;
// Take in the IContainer directly so that
// yes, you can use it as a service locator
public LogVisualizer(IContainer container)
{
_container = container;
}
// It's easy if you already know what the log
// type is
public string ToHtml<TLog>(TLog log)
{
return _container.GetInstance<IVisualizer<TLog>>()
.ToHtml(log);
}
public string ToHtml(object log)
{
// The ForObject() method uses the
// log.GetType() as the parameter to the open
// type Writer<T>, and then resolves that
// closed type from the container and
// casts it to IWriter for you
return _container.ForObject(log)
.GetClosedTypeOf(typeof (Writer<>))
.As<IWriter>()
.Write(log);
}
public string ToHtml2(object log)
{
// The ForGenericType() method is again creating
// a closed type of Writer<T> from the Container
// and casting it to IWriter
return _container.ForGenericType(typeof (Writer<>))
.WithParameters(log.GetType())
.GetInstanceAs<IWriter>()
.Write(log);
}
// The IWriter and Writer<T> class below are
// adapters to go from "object" to <T>() signatures
public interface IWriter
{
string Write(object log);
}
public class Writer<T> : IWriter
{
private readonly IVisualizer<T> _visualizer;
public Writer(IVisualizer<T> visualizer)
{
_visualizer = visualizer;
}
public string Write(object log)
{
return _visualizer.ToHtml((T) log);
}
}
}
+The two methods are almost identical in result with some slight differences:
+ForObject(object subject)
can only work with open types that have only one generic type parameter, and it will pass the argument subject
to the underlying Container
as an explicit argument so that you can inject that subject
object into the object graph being created.ForGenericType(Type openType)
is a little clumsier to use, but can handle any number of generic type parametersAs I recall, the following example was inspired by a question about how to use StructureMap to build out MongoDB MongoCollection objects from some sort of static builder or factory -- but I can't find the discussion on the mailing list as I write this today. This has come up often enough to justify its inclusion in the documentation.
+Say that you have some sort of persistence tooling that you primarily interact with through an interface like this one below, where TDocument
and TQuery
are classes in
+your persistent domain:
public interface IRepository<TDocument, TQuery>
{
}
+Great, StructureMap handles generic types just fine, so you can just register the various closed types and off you go. Except you can't because the way that your
+persistence tooling works requires you to create the IRepository<,>
objects with a static builder class like this one below:
public static class RepositoryBuilder
{
public static IRepository<TDocument, TQuery> Build<TDocument, TQuery>()
{
return new Repository<TDocument, TQuery>();
}
}
+StructureMap has an admittedly non-obvious way to handle this situation by creating a new subclass of Instance
that will "know" how to create the real Instance
for a closed
+type of IRepository<,>
.
First off, let's create a new Instance
type that knows how to build a specific type of IRepository<,>
by subclassing the LambdaInstance
type and providing a Func
to
+build our repository type with the static RepositoryBuilder
class:
public class RepositoryInstance<TDocument, TQuery> : LambdaInstance<IRepository<TDocument, TQuery>>
{
public RepositoryInstance() : base(() => RepositoryBuilder.Build<TDocument, TQuery>())
{
}
// This is purely to make the diagnostic views prettier
public override string Description
{
get
{
return "RepositoryBuilder.Build<{0}, {1}>()"
.ToFormat(typeof(TDocument).Name, typeof(TQuery).Name);
}
}
}
+As you've probably surmised, the custom RepositoryInstance
above is itself an open generic type and cannot be used directly until it has been closed. You could use this class directly if you have a very few document types like this:
var container = new Container(_ =>
{
_.For<IRepository<string, int>>().UseInstance(new RepositoryInstance<string, int>());
// or skip the custom Instance with:
_.For<IRepository<string, int>>().Use(() => RepositoryBuilder.Build<string, int>());
});
+To handle the problem in a more generic way, we can create a second custom subclass of Instance
for the open type IRepository<,>
that will help StructureMap understand how
+to build the specific closed types of IRepository<,>
at runtime:
public class RepositoryInstanceFactory : Instance
{
// This is the key part here. This method is called by
// StructureMap to "find" an Instance for a closed
// type of IRepository<,>
public override Instance CloseType(Type[] types)
{
// StructureMap will cache the object built out of this,
// so the expensive Reflection hit only happens
// once
var instanceType = typeof(RepositoryInstance<,>).MakeGenericType(types);
return Activator.CreateInstance(instanceType).As<Instance>();
}
// Don't worry about this one, never gets called
public override IDependencySource ToDependencySource(Type pluginType)
{
throw new NotSupportedException();
}
public override string Description
{
get { return "Build Repository<T, T1>() with RepositoryBuilder"; }
}
public override Type ReturnedType
{
get { return typeof(Repository<,>); }
}
}
+The key part of the class above is the CloseType(Type[] types)
method. At that point, we can determine the right type of RepositoryInstance<,>
to build the requested type of IRepository<,>
, then use some reflection to create and return that custom Instance
.
Here's a unit test that exercises and demonstrates this functionality from end to end:
+
[Fact]
public void show_the_workaround_for_generic_builders()
{
var container = new Container(_ =>
{
_.For(typeof(IRepository<,>)).Use(new RepositoryInstanceFactory());
});
container.GetInstance<IRepository<string, int>>()
.ShouldBeOfType<Repository<string, int>>();
Debug.WriteLine(container.WhatDoIHave(assembly: GetType().GetAssembly()));
}
+After requesting IRepository<string, int>
for the first time, the container configuration from Container.WhatDoIHave() is:
+=================================================================================================================================================== +PluginType Namespace Lifecycle Description Name +--------------------------------------------------------------------------------------------------------------------------------------------------- +IRepository<String, Int32> StructureMap.Testing.Acceptance Transient RepositoryBuilder.Build<String, Int32>() (Default) +--------------------------------------------------------------------------------------------------------------------------------------------------- +IRepository<TDocument, TQuery> StructureMap.Testing.Acceptance Transient Build Repository<T, T1>() with RepositoryBuilder (Default) +=================================================================================================================================================== ++
Several years ago I described an approach for using an Event Aggregator in a WPF application that relied on StructureMap interception to register any object that +StructureMap built with the active EventAggregator for the system if that object was recognized as a listener to the event aggregator. I thought that approach worked out quite well, so let's talk about how you could implement +that same design with the improved interception model introduced by StructureMap 3.0 (the event aggregator and StructureMap interception worked out well, +but I'm very happy now that I ditched the old WPF client and replaced it with a web application using React.js instead).
+First off, let's say that we're going to have this interface for our event aggregator:
+
public interface IEventAggregator
{
// Sending messages
void SendMessage<T>(T message);
void SendMessage<T>() where T : new();
// Explicit registration
void AddListener(object listener);
void RemoveListener(object listener);
}
+To register a listener for a particular type of event notification, you would implement an interface called IListener<T>
shown below
+and directly add that object to the IEventAggregator
:
public interface IListener<T>
{
void Handle(T message);
}
+In the application I'm describing, all of the listener objects were presenters or screen controls that were created by StructureMap, so it was convenient to allow StructureMap to register newly created objects with the IEventAggregator
in an activation interceptor.
What we want to do though is have an interception policy that only applies to any concrete type that implements some interface that
+closes IListener<T>
:
public class EventListenerRegistration : IInterceptorPolicy
{
public string Description
{
get { return "Adds the constructed object to the EventAggregator"; }
}
public IEnumerable<IInterceptor> DetermineInterceptors(Type pluginType, Instance instance)
{
if (instance.ReturnedType.FindInterfacesThatClose(typeof(IListener<>)).Any())
{
Expression<Action<IContext, object>> register =
(c, o) => c.GetInstance<IEventAggregator>().AddListener(o);
yield return new ActivatorInterceptor<object>(register);
}
}
}
+To see our new interception policy in action, see this unit test from GitHub:
+
[Fact]
public void use_the_event_listener_registration()
{
var container = new Container(x =>
{
x.Policies.Interceptors(new EventListenerRegistration());
x.For<IEventAggregator>().Use<EventAggregator>().Singleton();
});
var events = container.GetInstance<IEventAggregator>();
var listener = container.GetInstance<BooMessageListener>();
var message = new BooMessage();
events.SendMessage(message);
listener.Messages.Single().ShouldBeTheSameAs(message);
}
+
+ The current version of StructureMap will always be available on Nuget. See the Release Notes for more information.
-The original StructureMap.dll
has been broken up into a couple pieces. The main assembly will be targeting PCL compliance thanks to the diligent efforts of Frank Quednau, and that means that anything to do with ASP.Net or falls outside of the PCL core has been devolved into separate assemblies and eventually into different Nuget packages. This means that StructureMap 3.* will theoretically support WP8 and other versions of .Net for the very first time.
At this point StructureMap 3.* has been used on .Net 4, 4.5, and WP8. Nobody in the core StructureMap team is currently working with Xamarin mobile runtimes, but we are interested in verifying StructureMap on new platforms if any volunteers are interested.
-Binaries of StructureMap are available via NuGet:
-PM> Install-Package StructureMap
-
-StructureMap's source is hosted on GitHub. If you want to fix a bug or just want to tinker with an idea, we love receiving pull requests! Start by creating your own fork on Github.
-StructureMap needs FubuRake and Ripple for building the source. FubuRake is an OSS Ruby library to quickly stand up a fully functional, cross platform rake
script for a .Net codebase based on Fubu project standards. Ripple is a package manager that simplifies managing Nuget dependencies in your solution. Both dependencies are currently distributed through Ruby Gems and are part of the Fubu family. Before you continue you need to make sure that you have got Ruby installed.
git clone git://github.com/structuremap/structuremap.git
rake
.--Installing Ruby, Rake and RubyGems
-
--Installing Ruby will give you RubyGems and Rake out of the box. You can find installation guidance at the official Ruby language website or you could install Ruby via Chocolatey:
-
---
> cinst ruby
-- - -After you have Ruby, Rake and RubyGems installed you are good to go. The
-rake
build filerakefile.rb
(located in the root) will install al the other needed dependencies likeFubuRake
andRipple
, which are defined in theGemfile
(also located in the root). This file is used by another gem calledbundler
. Therake
build file will automatically installbundler
, which does the same for all the dependencies listed in theGemfile
, but only if they weren't already installed on your machine.
The current version of StructureMap will always be available on Nuget. See the Release Notes for more information.
+The original StructureMap.dll
has been broken up into a couple pieces. The main assembly will be targeting PCL compliance thanks to the diligent efforts of Frank Quednau, and that means that anything to do with ASP.Net or falls outside of the PCL core has been devolved into separate assemblies and eventually into different Nuget packages. This means that StructureMap 3.* will theoretically support WP8 and other versions of .Net for the very first time.
At this point StructureMap 3.* has been used on .Net 4, 4.5, WP8, and WP8.1.
+StructureMap 4.5+ will not work on Xamarin iOS because it depends on System.Reflection.Emit, which is not available in MonoTouch. StructureMap 4.4 works for at least basic scenarios on that platform. Nobody in the core StructureMap team is currently working with Xamarin mobile runtimes, but we are interested in verifying StructureMap on new platforms if any volunteers are interested in helping us out.
+Binaries of StructureMap are available via NuGet:
+PM> Install-Package StructureMap
+
+or if you need a strong named version of StructureMap:
+PM> Install-Package structuremap-signed
+
+The StructureMap team believes strong naming to be a blight upon the .Net land and we really wish folks would quit using it, but we understand that some circumstances absolutely require it.
+StructureMap's source is hosted on GitHub. If you want to fix a bug or just want to tinker with an idea, we love receiving pull requests! Start by creating your own fork on Github.
+The StructureMap build tooling has recently changed. See the GitHub README for more information on how to build and work with the StructureMap codebase.
+ +There are some terms that reoccur throughout the documentation and show up in the StructureMap API. Understanding these terms and how they relate to StructureMap isn't a prerequisite to using StructureMap, but it helps.
-Tools like StructureMap are generally known as Inversion of Control (IoC) Containers or Dependency Injection (DI) Containers. In the Java world they are also known as Lightweight Containers to differentiate them from the older EJB Containers.
-A container is a tool that can help you composing object graphs and managing their scope (lifecycle). Altough you can do Inversion of Control and Dependecy Injection manually, using tools like StructureMap makes you far more productive and succesfull in doing so.
-Obviously there is more to a container then resolving services and managing their scope, but in the core that's just what it is. Before you can do so you need to tell StructureMap, the container, how it must compose those objects graphs and what their lifecycle is. This is called registration and can be done in various mixed ways. The strongly recommend way would be using the Registry DSL. In your registration your basicaly mapping abstractions to concrete types and define their lifecycle.
-A simple example of a container using the Registry DSL:
-
- public class FooBarRegistry : Registry
- {
- public FooBarRegistry()
- {
- For<IFoo>().Use<Foo>();
- For<IBar>().Use<Bar>();
- }
- }
-
-
-
- var container = new Container(c => { c.AddRegistry<FooBarRegistry>(); });
-
-Because we didn't specify the lifecycle for both registrations, the default Transient
lifecycle will be used. This will instruct the container to create a new instance for every request for a plugin type IFoo
or IBar
.
More advanced features that the container can do are things like: Interception, Auto-Wiring, Forwarding Types.
-A nested container is used to mark the scope of short lived transactions or web requests and track and clean up objects implementing the IDisposable
interface for that operation.
You can ask a existing container to create a nested container for you like in the following example:
-
- using (var nested = someExistingContainer.GetNestedContainer())
- {
- // pull other objects from the nested container and do work with those services
- var service = nested.GetInstance<IService>();
- service.DoSomething();
- }
-
-For more detailed information about nested containers and their special properties you can read the <linkto:the-container/nested-containers]> topic.
-The term plugin type is used throughout the code and documentation to mean the type that you want to register or resolve. More generally this type is known as the service type. This type can be a concrete class or in most cases, it will be a form of abstraction like an abstract class or interface.
-The term plugged type means the actual concrete type that you get when you request the plugin type. This type must obviously implement the plugin type contract.
-In your registration you could have something like this:
-
- public class FooRegistry : Registry
- {
- public FooRegistry()
- {
- For<IFoo>().Use<Foo>();
- }
- }
-
-
-
-//For<PLUGINTYPE>().Use<PLUGGEDTYPE>()
-
- var container = new Container(c => { c.AddRegistry<FooRegistry>(); });
-
- container.GetInstance<IFoo>();
-
-//container.GetInstance<PLUGINTYPE>()
-
-If you request an object of IFoo
, you'll get an instance of the Foo
class. In this case, IFoo
is the plugin type (what you're asking for) and Foo
is the plugged type (the concrete class you'll get that fulfills, implements the plugin type contract).
This term you will not see so often because it's mostly used by StructureMap itself. A PluginFamily
represents a CLR type (the plugin type) that StructureMap can build, and all of the possible plugged types that implement the CLR type.
In the following code StructureMap internally creates one PluginFamily
of the plugin type IFoo
with two instances Foo
and SomeOtherFoo
, where Foo
is the default instance because it's registered through For<PLUGIN_TYPE>().Use<PLUGGED_TYPE>()
.
- var container = new Container(c =>
- {
- c.For<IFoo>().Use<Foo>();
- c.For<IFoo>().Add<SomeOtherFoo>();
- });
-
-Before StructureMap 3.0 you have probably seen the term used in an exception message when you request a plugin type that doesn't have a default instance defined.
-StructureMap Exception Code: 202
-No Default Instance defined for PluginFamily [plugin type]
-
-This specific exception message is gone in 3.0 because the exception messages were modernized in version 3.0 and.
-A PluginGraph
is the configuration model of the runtime configuration of a StructureMap container. The PluginGraph
model can be manipulated directly in StructureMap 3.0 for
-any kind of special convention that doesn't fit into the existing conventional support.
In StructureMap terms, an "Instance" is a configured and named strategy to build or locate a named object instance for a requested Plugin Type. An "Instance" does not automatically equate to a concrete type. For example, let's say that we're building a system to automate a warehouse. Our system might consume an interface called IShippingService that acts as a Gateway to various ways of shipping boxes out of our warehouse.
-
- public interface IShippingService
- {
- void ShipIt();
- }
-
-
-Our warehouse system might have to interact with three types of shipping: domestic, international, and intra-company or internal shipments. The internal shipping service runs in process with the warehouse application, but domestic and international shipping is done by invoking external web services. The registration of the IShippingService Instances might look like this:
-
- public class ShippingRegistry : Registry
- {
- public ShippingRegistry()
- {
- For<IShippingService>().AddInstances(x =>
- {
- x.Type<ShippingWebService>()
- .Ctor<string>("url").Is("a url")
- .Named("Domestic");
-
- x.Type<ShippingWebService>()
- .Ctor<string>("url").Is("a different url")
- .Named("International");
-
- x.Type<InternalShippingService>().Named("Internal");
- });
- }
- }
-
-
-In the registration code above, there are three "Instance's." You can access the various IShippingService Instance's by name:
-
- var container = new Container(new ShippingRegistry());
-
- // Accessing the IShippingService Instance's by name
- var internationalService = container.GetInstance<IShippingService>("International");
- var domesticService = container.GetInstance<IShippingService>("Domestic");
- var internalService = container.GetInstance<IShippingService>("Internal");
-
-
-Asking for the "International" or the "Domestic" instance of IShippingService will both return an object of type ShippingWebService, but the two objects will be differently configured with unique Url's.
-There is an actual class in StructureMap that represents an "Instance."
-When you call Container.GetInstance<T>("the instance that I want")
or Container.GetInstance<T>()
, the internal Container
object is locating the correct Instance object and then using the Instance's internal build plan to resolve or construct the actual object.
A StructureMap "Instance" is a close analogue for what many other IoC tools call a "Component."
-The power of an IoC container isn't just in building object graphs for you, it's also about scoping an object graph to what StructureMap calls a lifecycle. Think of it this way, -when you ask StructureMap for a service or much more commonly when StructureMap is filling a dependency behind the scenes, do you want:
-A Registry
or a sub class of Registry
is a class that let's you create reusable configuration for StructureMap containers.
StructureMap 3.0 features a complete rewrite of the ancient Profile functionality where you can create your base Container configuration with additional Profile -configuration that overrides one or more of the parent Container defaults. The Profile functionality was originally meant to handle difference between -development, testing, and production environments but has been more commonly used for multi-tenancy situations. Think of a Profile as an application or tenant mode.
-You'd never get anything done if you had to tell StructureMap how to build each and every constructor or setter dependency on every concrete class. Fortunately, StructureMap like -most IoC container tools, supports the concept of auto-wiring -- meaning that StructureMap can happily infer dependency requirements from constructor functions and setter -rules and fill those dependencies with the default configuration for the declared dependency type.
-Let's just see it in action:
-
- public interface Xman
- {
- }
-
- public class Cyclops : Xman
- {
- }
-
- public interface Avenger
- {
- }
-
- public class IronMan : Avenger
- {
- }
-
- public class CrossoverEvent
- {
- public Xman Xman { get; set; }
- public Avenger Avenger { get; set; }
-
- public CrossoverEvent(Xman xman, Avenger avenger)
- {
- Xman = xman;
- Avenger = avenger;
- }
- }
-
- public class UsingCrossover
- {
- [Test]
- public void showing_auto_wiring()
- {
- var container = new Container(x =>
- {
- x.For<Xman>().Use<Cyclops>();
- x.For<Avenger>().Use<IronMan>();
- });
-
- // Notice that at no point did we define how to
- // build CrossoverEvent.
- var @event = container.GetInstance<CrossoverEvent>();
- @event.Avenger.ShouldBeOfType<IronMan>();
- @event.Xman.ShouldBeOfType<Cyclops>();
- }
- }
-
-
-
-
- There are some terms that reoccur throughout the documentation and show up in the StructureMap API. Understanding these terms and how they relate to StructureMap isn't a prerequisite to using StructureMap, but it helps.
+Tools like StructureMap are generally known as Inversion of Control (IoC) Containers or Dependency Injection (DI) Containers. In the Java world they are also known as Lightweight Containers to differentiate them from the older EJB Containers.
+A container is a tool that can help you composing object graphs and managing their scope (lifecycle). Altough you can do Inversion of Control and Dependency Injection manually, using tools like StructureMap makes you far more productive and succesfull in doing so.
+Obviously there is more to a container than resolving services and managing their scope, but in the core that's just what it is. Before you can do so you need to tell StructureMap, the container, how it must compose those objects graphs and what their lifecycle is. This is called registration and can be done in various mixed ways. The strongly recommend way would be using the Registry DSL. In your registration you're basically mapping abstractions to concrete types and defining their lifecycle.
+A simple example of a container using the Registry DSL:
+
public class FooBarRegistry : Registry
{
public FooBarRegistry()
{
For<IFoo>().Use<Foo>();
For<IBar>().Use<Bar>();
}
}
+
var container = new Container(c => { c.AddRegistry<FooBarRegistry>(); });
+Because we didn't specify the lifecycle for both registrations, the default Transient
lifecycle will be used. This will instruct the container to create a new instance for every request for a plugin type IFoo
or IBar
.
More advanced features that the container can do are things like: Interception, Auto-Wiring, Forwarding Types.
+A nested container is used to mark the scope of short lived transactions or web requests and track and clean up objects implementing the IDisposable
interface for that operation.
You can ask an existing container to create a nested container for you like in the following example:
+
using (var nested = someExistingContainer.GetNestedContainer())
{
// pull other objects from the nested container and do work with those services
var service = nested.GetInstance<IService>();
service.DoSomething();
}
+For more detailed information about nested containers and their special properties you can read the Nested Containers (Per Request/Transaction) topic.
+The term plugin type is used throughout the code and documentation to mean the type that you want to register or resolve. More generally this type is known as the service type. This type can be a concrete class or in most cases, it will be a form of abstraction like an abstract class or interface.
+The term plugged type means the actual concrete type that you get when you request the plugin type. This type must obviously implement the plugin type contract.
+In your registration you could have something like this:
+
public class FooRegistry : Registry
{
public FooRegistry()
{
For<IFoo>().Use<Foo>();
}
}
+
//For<PLUGINTYPE>().Use<PLUGGEDTYPE>()
var container = new Container(c => { c.AddRegistry<FooRegistry>(); });
container.GetInstance<IFoo>();
//container.GetInstance<PLUGINTYPE>()
+If you request an object of IFoo
, you'll get an instance of the Foo
class. In this case, IFoo
is the plugin type (what you're asking for) and Foo
is the plugged type (the concrete class you'll get that fulfills, implements the plugin type contract).
This term you will not see so often because it's mostly used by StructureMap itself. A PluginFamily
represents a CLR type (the plugin type) that StructureMap can build, and all of the possible plugged types that implement the CLR type.
In the following code StructureMap internally creates one PluginFamily
of the plugin type IFoo
with two instances Foo
and SomeOtherFoo
, where Foo
is the default instance because it's registered through For<PLUGIN_TYPE>().Use<PLUGGED_TYPE>()
.
var container = new Container(c =>
{
c.For<IFoo>().Use<Foo>();
c.For<IFoo>().Add<SomeOtherFoo>();
});
+Before StructureMap 3.0 you have probably seen the term used in an exception message when you request a plugin type that doesn't have a default instance defined.
+StructureMap Exception Code: 202
+No Default Instance defined for PluginFamily [plugin type]
+
+This specific exception message is gone in 3.0 because the exception messages were modernized.
+A PluginGraph
is the configuration model of the runtime configuration of a StructureMap container. The PluginGraph
model can be manipulated directly in StructureMap 3.0 for
+any kind of special convention that doesn't fit into the existing conventional support.
In StructureMap terms, an "Instance" is a configured and named strategy to build or locate a named object instance for a requested Plugin Type. An "Instance" does not automatically equate to a concrete type. For example, let's say that we're building a system to automate a warehouse. Our system might consume an interface called IShippingService that acts as a Gateway to various ways of shipping boxes out of our warehouse.
+
public interface IShippingService
{
void ShipIt();
}
+Our warehouse system might have to interact with three types of shipping: domestic, international, and intra-company or internal shipments. The internal shipping service runs in process with the warehouse application, but domestic and international shipping is done by invoking external web services. The registration of the IShippingService Instances might look like this:
+
public class ShippingRegistry : Registry
{
public ShippingRegistry()
{
For<IShippingService>().AddInstances(x =>
{
x.Type<ShippingWebService>()
.Ctor<string>("url").Is("a url")
.Named("Domestic");
x.Type<ShippingWebService>()
.Ctor<string>("url").Is("a different url")
.Named("International");
x.Type<InternalShippingService>().Named("Internal");
});
}
}
+In the registration code above, there are three "Instances." You can access the various IShippingService Instance's by name:
+
var container = new Container(new ShippingRegistry());
// Accessing the IShippingService Instance's by name
var internationalService = container.GetInstance<IShippingService>("International");
var domesticService = container.GetInstance<IShippingService>("Domestic");
var internalService = container.GetInstance<IShippingService>("Internal");
+Asking for the "International" or the "Domestic" instance of IShippingService will both return an object of type ShippingWebService, but the two objects will be differently configured with unique Url's.
+There is an actual class in StructureMap that represents an "Instance."
+When you call Container.GetInstance<T>("the instance that I want")
or Container.GetInstance<T>()
, the internal Container
object is locating the correct Instance object and then using the Instance's internal build plan to resolve or construct the actual object.
A StructureMap "Instance" is a close analogue for what many other IoC tools call a "Component."
+The power of an IoC container isn't just in building object graphs for you, it's also about scoping an object graph to what StructureMap calls a lifecycle. Think of it this way: +when you ask StructureMap for a service or (much more commonly) when StructureMap is filling a dependency behind the scenes, do you want:
+A Registry
or a sub class of Registry
is a class that let's you create reusable configuration for StructureMap containers.
StructureMap 3.0 features a complete rewrite of the ancient Profile functionality where you can create your base Container configuration with additional Profile +configuration that overrides one or more of the parent Container defaults. The Profile functionality was originally meant to handle differences between +development, testing, and production environments but has been more commonly used for multi-tenancy situations. Think of a Profile as an application or tenant mode.
+You'd never get anything done if you had to tell StructureMap how to build each and every constructor or setter dependency on every concrete class. Fortunately, StructureMap like +most IoC container tools, supports the concept of auto-wiring -- meaning that StructureMap can happily infer dependency requirements from constructor functions and setter +rules and fill those dependencies with the default configuration for the declared dependency type.
+Let's just see it in action:
+
public interface Xman
{
}
public class Cyclops : Xman
{
}
public interface Avenger
{
}
public class IronMan : Avenger
{
}
public class CrossoverEvent
{
public Xman Xman { get; set; }
public Avenger Avenger { get; set; }
public CrossoverEvent(Xman xman, Avenger avenger)
{
Xman = xman;
Avenger = avenger;
}
}
public class UsingCrossover
{
[Fact]
public void showing_auto_wiring()
{
var container = new Container(x =>
{
x.For<Xman>().Use<Cyclops>();
x.For<Avenger>().Use<IronMan>();
});
// Notice that at no point did we define how to
// build CrossoverEvent.
var @event = container.GetInstance<CrossoverEvent>();
@event.Avenger.ShouldBeOfType<IronMan>();
@event.Xman.ShouldBeOfType<Cyclops>();
}
}
+
+ StructureMap was originally conceived in 2002 as the world's greatest object/relational mapping tool (and frankly a way for me to -prove to prospective employers that I could actually code so I could move on from my non-coding architect position at that time). -What exists today is the descendent of the overly grandiose configuration subsystem for that failed ORM concept (hence the name "StructureMap").
-StructureMap was resurrected in the spring of 2004 as an "Inversion of Control" tool after I read about the http://picocontainer.codehaus.org IoC tool written in Java by several folks at my company at that time. In June of 2004 StructureMap went into its first production application and was also publicly -released on the old Sourceforge.net website. As such, StructureMap is the oldest, continuously used IoC tool for .Net development.
-The current release (3.*) represents the lessons learned from over 10 years of usage and other than a handful of class names bears very little -internal resemblance to the original codebase.
-StructureMap moved to GitHub in 2010 and is now distributed via Nuget.
-To learn more about the StructureMap journey, see the Joys and Pains of a Long Lived Codebase on InfoQ from QCon 2008, or check out -Jeremy Miller's updated retrospective talk at CodeMash 2015.
- - -StructureMap was originally conceived in 2002 as the world's greatest object/relational mapping tool (and frankly a way for me to +prove to prospective employers that I could actually code so I could move on from my non-coding architect position at that time). +What exists today is the descendent of the overly grandiose configuration subsystem for that failed ORM concept (hence the name "StructureMap").
+StructureMap was resurrected in the spring of 2004 as an "Inversion of Control" tool after I read about the http://picocontainer.codehaus.org IoC tool written in Java by several folks at my company at that time. In June of 2004 StructureMap went into its first production application and was also publicly +released on the old Sourceforge.net website. As such, StructureMap is the oldest, continuously used IoC tool for .Net development.
+The current release (3.*) represents the lessons learned from over 10 years of usage and other than a handful of class names bears very little +internal resemblance to the original codebase.
+StructureMap moved to GitHub in 2010 and is now distributed via Nuget.
+To learn more about the StructureMap journey, see the Joys and Pains of a Long Lived Codebase on InfoQ from QCon 2008, or check out +Jeremy Miller's updated retrospective talk at CodeMash 2015.
+ +StructureMap is the oldest, continuously used IoC/DI container for .Net dating back to its first public release and production usage all the way back in June 2004 on .Net 1.1. -The current 3.* release represents 10+ years of lessons learned in the StructureMap and greater .Net community -- while also wiping away a great deal of legacy design +The current 4.* release represents 12+ years of lessons learned in the StructureMap and greater .Net community -- while also wiping away a great deal of legacy design decisions that no longer make sense today.
@@ -83,7 +91,28 @@Most users will never need to implement a custom Instance
type, but it does come up here and there. The easiest way is probably to
+subclass LambdaInstance
as shown below:
public class FuncInstance<T> : LambdaInstance<Func<T>>
{
// Pass a Func<IContext, T> into the base constructor
// Use a static method for cleaner syntax to avoid the
// nasty Lambda syntax formatting as needed
public FuncInstance() : base(s => s.GetInstance<IContainer>().GetInstance<T>)
{
}
public override string Description
{
get { return "Constructor for Func<{0}>".ToFormat(typeof (T).Name); }
}
}
+The other common customization is as a generic builder template
+If neither of these approaches will easily work for your custom Instance
, you may want to contact the StructureMap team
+via the gitter link above and we can help walk you through a custom subclass of Instance
-- or more likely, talk you out
+of it somehow.
New to StructureMap 4.0 is the Instance.ToNamedClone(name)
method that is used behind the scenes by the Handling Missing Named Instances feature.
public virtual Instance ToNamedClone(string name)
+Custom Instance types can override this method to provide a brand new Instance for a name. This functionality may be useful for multi-tenancy situations.
+ +I'm thinking that this page needs to cover:
-Want to see more integrations or samples of how to integrate StructureMap with various .Net development tools? Let us know in Gitter or Github, or better yet, we take pull requests for documentation.
+The StructureMap team recommends the StructureMap.MVC5 NuGet package for integrating +StructureMap into ASP.NET MVC. The design is necessarily odd to work around ASP.NET limitations, but you do get the all +important "nested container per HTTP request" pattern that we recommend.
+The easiest way to integrate StructureMap with ASP.NET Web API is with the WebApi.StructureMap NuGet package. This package requires StructureMap 4.1 or higher. +Use the StructureMap.WebApi2 NuGet package for older versions of StructureMap or combined ASP.NET MVC and Web API projects where you already use the StructureMap.MVC5 NuGet package.
+See the StructureMap.Microsoft.DependencyInjection project and NuGet package for integration with ASP.NET Core.
+Use the NServiceBus StructureMap NuGet package for integrating StructureMap 3 into +NServiceBus.
+NancyFx provides the Nancy.Bootstrappers.StructureMap NuGet package. The early +versions of the NancyFx integration with StructureMap were deeply flawed but improved in later versions, so do make sure that you are using the latest version of the bootstrapper.
+Use the MassTransit.StructureMap NuGet package. Unfortunately, this package +depends on the signed version of StructureMap, so prepare yourself for version conflicts, +binding redirects, and the fusion log viewer. See the MassTransit documentation on using StructureMap for more information.
+The best example is this blog post from Jimmy Bogard.
+See My AutoMapper setup for StructureMap from Martijn Burgers.
+ +All of the samples from this topic are part of the user acceptance tests in the main codebase. There is also another example of using an interception policy with +open generic types at the bottom of Generic Types
+Improving the interception facilities and the means of applying decorators during object construction was one of the primary +goals of the big 3.0 release and is significantly different than the older 2.5/2.6 model.
+Interception in StructureMap really comes +in two basic flavors:
+Interceptors can be configured explicitly on a single Instance
registration, on all registrations to a PluginFamily
, or conventionally
+to any concrete type implementing an interface, inheriting from a certain base class, or by some sort of user-supplied
+criteria.
Any type of Instance
can be intercepted, meaning that even object literal values supplied to StructureMap at registration can be
+intercepted when they are resolved as dependencies or through service location calls.
See the Glossary for a refresher on terms like Instance
and PluginFamily
.
Also see Working with the IContext at Build Time for more information about using the Container
state within interception.
For right now, all activation interceptors are either using or subclassing the ActivatorInterceptor<T> class.
+This class has two constructor functions that interest us:
+To create an activator interceptor that acts on an object that can be cast to type T
:
public ActivatorInterceptor(Expression<Action<T>> action, string description = null)
+To create an activator interceptor that acts on an object that can be cast to type T
and
+also uses the IContext service supplied by StructureMap itself.
public ActivatorInterceptor(Expression<Action<IContext, T>> action, string description = null)
{
_action = action;
_description = description;
}
+In both cases, the description
is optional and is only used for diagnostic purposes in the build plan visualization. If
+omitted, StructureMap tries to do a ToString()
on the Expression for the description and that frequently suffices to understand what's going on in the build plan.
Please note that the Lambda supplied to ActivatorInterceptor<T>
must be a .Net Expression so cannot be a multi-line Lambda.
+You can get around this limitation for more complex activation needs by simply making a wrapping method and using that
+to express the activation.
To demonstrate a decorator in action, say that we have an interface called IWidget
, and when we build any instance
+of IWidget
we want those objects decorated by another type of IWidget
that I clumsily named WidgetHolder
in the
+acceptance tests:
public class WidgetHolder : IWidget
{
private readonly IWidget _inner;
public WidgetHolder(IWidget inner)
{
_inner = inner;
}
public IWidget Inner
{
get { return _inner; }
}
}
+Now, to see the decorator mechanism in action:
+
[Fact]
public void decorator_example()
{
var container = new Container(_ =>
{
// This usage adds the WidgetHolder as a decorator
// on all IWidget registrations and makes AWidget
// the default
_.For<IWidget>().DecorateAllWith<WidgetHolder>();
_.For<IWidget>().Use<AWidget>();
});
container.GetInstance<IWidget>()
.ShouldBeOfType<WidgetHolder>()
.Inner.ShouldBeOfType<AWidget>();
}
+In effect, doing a decorator this way has the same effect (and build plan) as:
+
var container = new Container(_ =>
{
_.For<IWidget>().Use<WidgetHolder>()
.Ctor<IWidget>().Is<AWidget>();
});
+The simplest usage is to just declare a type that will be the decorating type like we did above, but if you need some
+other mechanism for decorators like runtime AOP interception or you want to build the decorating object yourself, StructureMap
+provides the FuncInterceptor<T>
type where T
is the type you want to decorate.
These objects can be created in two ways, by a user-supplied Expression<Func<T, T>>
and optional description:
public FuncInterceptor(Expression<Func<T, T>> expression, string description = null)
+and by a user-supplied Expression<Func<IContext, T, T>>
and optional description.
public FuncInterceptor(Expression<Func<IContext, T, T>> expression, string description = null)
+In both cases, the description
field is only used for diagnostic purposes.
The Registry DSL includes shorthand methods for the most common ways of configuring decorators
+and activators by an individual Instance
or by matching on implementing types. For more customized interception policies
+that don't fit these mechanisms, StructureMap allows you to directly define an interception policy with a class
+implementing this interface below:
public interface IInterceptorPolicy : IDescribed
{
IEnumerable<IInterceptor> DetermineInterceptors(Type pluginType, Instance instance);
}
+For a simple example, let's say that we want to decorate any IWidget
object with the
+WidgetHolder
class from earlier. We could build a small custom interceptor policy
+like this one:
public class CustomInterception : IInterceptorPolicy
{
public string Description
{
get { return "good interception policy"; }
}
public IEnumerable<IInterceptor> DetermineInterceptors(Type pluginType, Instance instance)
{
if (pluginType == typeof(IWidget))
{
// DecoratorInterceptor is the simple case of wrapping one type with another
// concrete type that takes the first as a dependency
yield return new DecoratorInterceptor(typeof(IWidget), typeof(WidgetHolder));
}
}
}
+To use this custom interception policy, use the Policies.Interceptor()
methods like this example:
[Fact]
public void use_a_custom_interception_policy()
{
var container = new Container(x =>
{
x.Policies.Interceptors(new CustomInterception());
x.For<IWidget>().Use<AWidget>();
});
container.GetInstance<IWidget>()
.ShouldBeOfType<WidgetHolder>()
.Inner.ShouldBeOfType<AWidget>();
}
+As a helper for creating your own interception policies, you can also use the InterceptorPolicy<T>
base class
+to conventionally apply some sort of IInterceptor
to any number of Instance's
:
public InterceptorPolicy(IInterceptor interceptor, Func<Instance, bool> filter = null)
+Here's an example of InterceptorPolicy<T>
in usage from the acceptance tests:
[Fact]
public void apply_policy_selectively_with_a_func()
{
var activator1 = new ActivatorInterceptor<ITarget>(x => x.Activate());
var policy = new InterceptorPolicy<ITarget>(activator1, i => i.Name.StartsWith("A"));
var container = new Container(x =>
{
x.Policies.Interceptors(policy);
x.For<ITarget>().AddInstances(targets =>
{
targets.Type<ATarget>().Named("A");
targets.Type<ATarget>().Named("A1");
targets.Type<ATarget>().Named("A2");
targets.Type<ATarget>().Named("B");
targets.Type<ATarget>().Named("C");
targets.Type<ATarget>().Named("D");
});
});
container.GetInstance<ITarget>("A").ShouldBeOfType<ATarget>().WasActivated.ShouldBeTrue();
container.GetInstance<ITarget>("A1").ShouldBeOfType<ATarget>().WasActivated.ShouldBeTrue();
container.GetInstance<ITarget>("A2").ShouldBeOfType<ATarget>().WasActivated.ShouldBeTrue();
container.GetInstance<ITarget>("B").ShouldBeOfType<ATarget>().WasActivated.ShouldBeFalse();
container.GetInstance<ITarget>("C").ShouldBeOfType<ATarget>().WasActivated.ShouldBeFalse();
container.GetInstance<ITarget>("D").ShouldBeOfType<ATarget>().WasActivated.ShouldBeFalse();
}
public class ATarget : ITarget
{
public void Activate()
{
WasActivated = true;
}
public bool WasActivated { get; set; }
public void Debug()
{
throw new NotImplementedException();
}
}
+Some quick things to note:
+InterceptorPolicy<T>
will only apply if the pluginType
matches T
InterceptorPolicy<T>
will apply to any concrete type returned by an Instance
that can be
+cast to T
Let's say that in your system you have a marker interface or in this case an abstract class that exposes a single
+Activate()
method to start up stateful, long-running services created within your container:
public abstract class Activateable
{
public bool Activated { get; set; }
public void Activate()
{
Activated = true;
}
}
+An implementation of Activateable
from StructureMap's unit tests is shown below:
public class AWidget : Activateable, IWidget
{
}
+If you decide that you'd like StructureMap to call the Activate()
method on any object it creates as
+part of its object creation and resolution process, we can register an interception policy in a Registry
+like this:
[Fact]
public void activate_by_action()
{
var container = new Container(x =>
{
x.For<IWidget>().Use<AWidget>();
x.For<Activateable>()
.OnCreationForAll("Mark the object as activated", o => o.Activated = true);
});
container.GetInstance<IWidget>()
.ShouldBeOfType<AWidget>()
.Activated.ShouldBeTrue();
}
+There are several overloads of OnCreationForAll()
covering cases with and without IContext
As shown above, you can use the Registry.For<T>().DecorateAllWith<TDecorator>()
to apply decorators to all Instance's
+registered to a Plugin Type
:
[Fact]
public void decorate_with_type()
{
var container = new Container(x =>
{
x.For<IWidget>().DecorateAllWith<WidgetHolder>();
x.For<IWidget>().Use<AWidget>();
});
container.GetInstance<IWidget>()
.ShouldBeOfType<WidgetHolder>()
.Inner
.ShouldBeOfType<AWidget>();
}
+There are also several other overloads of DecorateAllWith()
for user supplied expressions, filters, and descriptions. See the
+acceptance tests for interception in the StructureMap codebase for many more sample usages.
You can also define interceptors directly to individual Instance's
inside of a StructureMap Registry
using the
+OnCreation()
and DecorateWith
methods or the more generic Instance.AddInterceptor()
method. Here is some sample
+usage from StructureMap's unit tests on interception:
_container = new Container(r =>
{
r.For<ContextRecorder>().Use(recorder);
r.For<IService>().AddInstances(x =>
{
x.Type<ColorService>()
// Registers an activation action on this Instance
.OnCreation("last service", s => _lastService = s)
.Named("Intercepted")
.Ctor<string>("color").Is("Red");
x.Type<ColorService>()
// Activation using IContext
.OnCreation("last touched", (c, s) => c.GetInstance<ContextRecorder>().WasTouched = true)
.Named("InterceptedWithContext")
.Ctor<string>("color").Is("Red");
x.Type<ColorService>()
.Named("NotIntercepted")
.Ctor<string>("color").Is("Blue");
x.Object(new ColorService("Yellow"))
.Named("Yellow")
.OnCreation("set the last service", s => _lastService = s);
x.ConstructedBy(() => new ColorService("Purple")).Named("Purple")
// Applies a decorator to this instance. Not sure *why*
// you'd want to do it this way
.DecorateWith(s => new DecoratorService(s));
x.ConstructedBy(() => new ColorService("Purple")).Named("DecoratedWithContext")
// Fancier decorator
.DecorateWith("decorated with context", (c, s) =>
{
c.GetInstance<ContextRecorder>().WasTouched = true;
return new DecoratorService(s);
});
x.Type<ColorService>().Named("Decorated").DecorateWith(
s => new DecoratorService(s))
.Ctor<string>("color").Is("Orange");
x.Object(new ColorService("Yellow")).Named("Bad")
.OnCreation("throw exception", obj => { throw new Exception("Bad!"); });
});
+
+ TODO(Write some content!)
- + -Improving the exception messages was one of the primary goals of the big StructureMap 3.0 release. StructureMap exceptions should +show a "StructureMap-specific stacktrace" describing where in the object graph StructureMap was when an exception occurred, while +trying hard not to obscure the actual problems. In some cases, StructureMap will append diagnostic views +to the exception output. If you are still using StructureMap 2.5-2.6, the better exception messages alone are a justification for upgrading.
+StructureMap throws a couple custom exceptions, all of which implement a base StructureMapException
type:
StructureMapBuildException
-- a failure was detected during an attempt to build or resolve a requested object or dependency, but outside of
+StructureMap code. This exception wraps the actual exception and adds StructureMap-specific contextual information. Always check the inner
+exception when this exception is thrown.StructureMapInterceptorException
-- a configured interceptor failed during object construction. See the inner exception.StructureMapBuildPlanException
-- StructureMap is missing some kind of configuration or needs more explicit registrations in order to
+build an Instance
. In a few cases, this exception will be thrown if StructureMap cannot create and compile a Func
internally for the
+Instance.
StructureMapConfigurationException
-- thrown by the container validation mechanismTODO(Write some content!)
- + -Unless designated otherwise, StructureMap uses Transient as the default scope for all configured Instance's.
-The resolution of the lifecycle for any given Instance is to check:
-The lifecycle precedence rules and the syntax for configuring object lifecycles are shown below:
-
- [Test]
- public void lifecycle_precedence()
- {
- var container = new Container(x =>
- {
- x.For<IWidget>().Use<AWidget>();
-
- // Configure the default lifecycle for
- // a PluginType (Rule)
- x.For<Rule>().Singleton();
- x.For<Rule>().Add<ARule>().Named("C");
-
- // Configure the lifecycle for a single Instance
- x.For<Rule>().Add<ARule>().Named("A").Transient();
- x.For<Rule>().Add<ARule>().Named("B").AlwaysUnique();
- });
-
- // The default lifecycle is Transient
- container.Model.For<IWidget>().Default
- .Lifecycle.ShouldBeOfType<TransientLifecycle>();
-
- // Override at the Family
- container.Model.For<Rule>().Lifecycle.ShouldBeOfType<SingletonLifecycle>();
- container.Model.For<Rule>().Find("C").Lifecycle.ShouldBeOfType<SingletonLifecycle>();
-
- // 'C' is the default lifecycle for Rule (Singleton)
- container.GetInstance<Rule>("C")
- .ShouldBeTheSameAs(container.GetInstance<Rule>("C"));
-
- // 'A' is a transient
- container.GetInstance<Rule>("A")
- .ShouldNotBeTheSameAs(container.GetInstance<Rule>("A"));
-
- using (var nested = container.GetNestedContainer())
- {
- // 'B' is always unique
- nested.GetInstance<Rule>("B")
- .ShouldNotBeTheSameAs(nested.GetInstance<Rule>("B"));
- }
- }
-
-
-
-
- Unless designated otherwise, StructureMap uses Transient as the default scope for all configured Instance's.
+The resolution of the lifecycle for any given Instance is to check:
+The lifecycle precedence rules and the syntax for configuring object lifecycles are shown below:
+
[Fact]
public void lifecycle_precedence()
{
var container = new Container(x =>
{
x.For<IWidget>().Use<AWidget>();
// Configure the default lifecycle for
// a PluginType (Rule)
x.For<Rule>().Singleton();
x.For<Rule>().Add<ARule>().Named("C");
// Configure the lifecycle for a single Instance
x.For<Rule>().Add<ARule>().Named("A").Transient();
x.For<Rule>().Add<ARule>().Named("B").AlwaysUnique();
});
// The default lifecycle is Transient
container.Model.For<IWidget>().Default
.Lifecycle.ShouldBeOfType<TransientLifecycle>();
// Override at the Family
container.Model.For<Rule>().Lifecycle.ShouldBeOfType<SingletonLifecycle>();
container.Model.For<Rule>().Find("C").Lifecycle.ShouldBeOfType<SingletonLifecycle>();
// 'C' is the default lifecycle for Rule (SingletonThing)
container.GetInstance<Rule>("C")
.ShouldBeTheSameAs(container.GetInstance<Rule>("C"));
// 'A' is a transient
container.GetInstance<Rule>("A")
.ShouldNotBeTheSameAs(container.GetInstance<Rule>("A"));
using (var nested = container.GetNestedContainer())
{
// 'B' is always unique
nested.GetInstance<Rule>("B")
.ShouldNotBeTheSameAs(nested.GetInstance<Rule>("B"));
}
}
+New in StructureMap 4.0 are some simple attributes to mark either a complete Plugin Type or a single Instance as either +a singleton or using the always unique lifecycle:
+The usage is shown below:
+
[AlwaysUnique]
public interface IShouldBeUnique { }
[Singleton] // because the most wonderful thing about Tiggers is that I'm the only one....
public class Tigger { }
+See Using Attributes for Configuration for information about adding your own custom attibutes for other lifecycles.
+ +Lifecycle's in StructureMap are pluggable. To create your own custom lifecycle, make an implementation of the ILifecycle
interface like this one:
- public class CustomLifecycle : ILifecycle
- {
- public static LifecycleObjectCache Cache = new LifecycleObjectCache();
-
- public string Description
- {
- get { return "Custom"; }
- }
-
- public void EjectAll(ILifecycleContext context)
- {
- // Here you'd remove all the existing objects
- // from the cache and call IDisposable.Dispose()
- // as appropriate
- }
-
- public IObjectCache FindCache(ILifecycleContext context)
- {
- // using the context, "find" the appropriate
- // IObjectCache object
- return Cache;
- }
- }
-
-
-Registering your custom lifecycle can be done like this:
-
- public class UsingCustomLifecycle : Registry
- {
- public UsingCustomLifecycle()
- {
- // at the Plugin Type level
- For<IService>().LifecycleIs<CustomLifecycle>();
-
- // at the Instance level
- For<IService>().Use<AService>()
- .LifecycleIs<CustomLifecycle>();
- }
- }
-
-
-Most of the built in ILifecycle
implementations use LifecycleObjectCache
internally, but you may also need to create your own IObjectCache
implementation.
Lifecycles in StructureMap are pluggable. To create your own custom lifecycle, make an implementation of the ILifecycle
interface like this one:
public class CustomLifecycle : ILifecycle
{
public static LifecycleObjectCache Cache = new LifecycleObjectCache();
public string Description
{
get { return "Custom"; }
}
public void EjectAll(ILifecycleContext context)
{
// Here you'd remove all the existing objects
// from the cache and call IDisposable.Dispose()
// as appropriate
}
public IObjectCache FindCache(ILifecycleContext context)
{
// using the context, "find" the appropriate
// IObjectCache object
return Cache;
}
}
+Registering your custom lifecycle can be done like this:
+
public class UsingCustomLifecycle : Registry
{
public UsingCustomLifecycle()
{
// at the Plugin Type level
For<IService>().LifecycleIs<CustomLifecycle>();
// at the Instance level
For<IService>().Use<AService>()
.LifecycleIs<CustomLifecycle>();
}
}
+Most of the built in ILifecycle
implementations use LifecycleObjectCache
internally, but you may also need to create your own IObjectCache
implementation.
One of the most valuable functions of using an IoC container tool is its ability to manage the object lifecycle (creating and disposing objects) and scoping (shared objects) -of your system's services so you can focus on the actual functionality instead of busy work.
-Some services like data cache's and event aggregators in your system will need to be shared across requests, screens, and handlers. -Other services should be created new every time you ask the container for one. Another set of services need to be scoped to an HTTP request or a logical transaction such that -every request to the container for a service originating within the context of a single HTTP request gets the same object instance.
-In all the cases above, StructureMap will assemble object graphs for you using the correct scoping of each dependency. Likewise, in some cases, StructureMap can help you
-with object cleanup by calling IDisposable.Dispose()
as appropriate when an object lifecyle is completed.
In the bad old days, we used the infamous Singleton pattern -as shown below for objects that really needed to be scoped as one single instance for the entire system:
-
- public class EvilSingleton
- {
- public static readonly EvilSingleton Instance = new EvilSingleton();
-
- private EvilSingleton()
- {
- }
-
- public void DoSomething()
- {
- // do something with the static data here
- }
- }
-
-
- public class EvilSingletonUser
- {
- public void DoWork()
- {
- EvilSingleton.Instance.DoSomething();
- }
- }
-
-
-The code above isn't terribly difficult to write or understand, but using a Singleton has some negative effects on your code as explained in Singletons are Evil and my own writing at Chill out on the Singleton Fetish.
-Instead, let's just use StructureMap to handle the singleton scoping instead and rewrite the code sample above as:
-
- public interface ISingletonDependency
- {
- void DoSomething();
- }
-
- public class Configuration : Registry
- {
- public Configuration()
- {
- // Tell StructureMap that all types
- // of ISingletonDependency are
- // to be scoped as "singletons"
- For<ISingletonDependency>()
- .Singleton();
- }
- }
-
- // This version of the class just uses constructor
- // injection to get an object instance of
- // ISingletonDependency.
- public class DependencyUser
- {
- private readonly ISingletonDependency _dependency;
-
- public DependencyUser(ISingletonDependency dependency)
- {
- _dependency = dependency;
- }
- }
-
-
-The big advantage to the second, StructureMap-managed singleton scoping is that my DependencyUser
class does not have to have any knowledge of
-how the ISingletonDependency
object is built and certainly no coupling to the hard Singleton mechanics from the first sample that was so harmful in the past.
One of the most valuable functions of using an IoC container tool is its ability to manage the object lifecycle (creating and disposing objects) and scoping (shared objects) +of your system's services so you can focus on the actual functionality instead of busy work.
+Some services like data cache's and event aggregators in your system will need to be shared across requests, screens, and handlers. +Other services should be created new every time you ask the container for one. Another set of services need to be scoped to an HTTP request or a logical transaction such that +every request to the container for a service originating within the context of a single HTTP request gets the same object instance.
+In all the cases above, StructureMap will assemble object graphs for you using the correct scoping of each dependency. Likewise, in some cases, StructureMap can help you
+with object cleanup by calling IDisposable.Dispose()
as appropriate when an object lifecyle is completed.
In the bad old days, we used the infamous Singleton pattern +as shown below for objects that really needed to be scoped as one single instance for the entire system:
+
public class EvilSingleton
{
public static readonly EvilSingleton Instance = new EvilSingleton();
private EvilSingleton()
{
}
public void DoSomething()
{
// do something with the static data here
}
}
public class EvilSingletonUser
{
public void DoWork()
{
EvilSingleton.Instance.DoSomething();
}
}
+The code above isn't terribly difficult to write or understand, but using a Singleton has some negative effects on your code as explained in Singletons are Evil and my own writing at Chill out on the Singleton Fetish.
+Instead, let's just use StructureMap to handle the singleton scoping instead and rewrite the code sample above as:
+
public class SingletonService { }
public class SingletonUser
{
public SingletonUser(SingletonService singleton)
{
}
}
public class SingletonScopeRegistry : Registry
{
public SingletonScopeRegistry()
{
For<SingletonService>().Singleton();
}
}
+The big advantage to the second, StructureMap-managed singleton scoping is that my DependencyUser
class does not have to have any knowledge of
+how the ISingletonDependency
object is built and certainly no coupling to the hard Singleton mechanics from the first sample that was so harmful in the past.
Out of the box, the core StructureMap assembly supports these lifecycles:
-Older versions of StructureMap referred to Transient as PerRequest, which might be a more accurate reflection of how this lifecycle behaves but
-causes some confusion with ASP.Net HTTP scoping. The easiest way to think of Transient is that a single object instance will be created for each top level
-call to Container.GetInstance()
(or any other object resolution method on the IContainer
interface). Transient objects resolved from a nested container, Transient's are scoped to the lifecycle
-of the nested container itself. See Nested Containers (Per Request/Transaction) for more information.
The following unit test demonstrates how Transient lifecycles work in both root and nested containers.
-
- [Test]
- public void Transient()
- {
- var c = new Container(x => { x.For<IService>().Use<Service>().Transient(); });
-
- // In a normal container, you get a new object
- // instance of the Service class in subsequent
- // requests
- c.GetInstance<IService>()
- .ShouldNotBeTheSameAs(c.GetInstance<IService>())
- .ShouldNotBeTheSameAs(c.GetInstance<IService>());
-
- // Within a nested container, 'Transient' now
- // means within the Nested Container.
- // A nested container is effectively one request
- using (var nested = c.GetNestedContainer())
- {
- nested.GetInstance<IService>()
- .ShouldBeTheSameAs(nested.GetInstance<IService>())
- .ShouldBeTheSameAs(nested.GetInstance<IService>());
- }
- }
-
-
-Also note that a transient dependency will
-be created exactly once in an object graph resolved from IContainer.GetInstance(Type)
. Imagine that you are building an
-object graph with various objects that all need to apply some work to a shared unit of work object (think NHibernate's ISession, Entity Framework's DbContext, RavenDb's IDocumentSession):
- public interface IUnitOfWork
- {
- }
-
- public class DefaultUnitOfWork : IUnitOfWork
- {
- }
-
- public class Worker1
- {
- public IUnitOfWork Uow { get; set; }
-
- public Worker1(IUnitOfWork uow)
- {
- Uow = uow;
- }
- }
-
- public class Worker2
- {
- public IUnitOfWork Uow { get; set; }
-
- public Worker2(IUnitOfWork uow)
- {
- Uow = uow;
- }
- }
-
- public class WorkerCoordinator
- {
- public IUnitOfWork Uow { get; set; }
- public Worker1 Worker1 { get; set; }
- public Worker2 Worker2 { get; set; }
-
- public WorkerCoordinator(IUnitOfWork uow, Worker1 worker1, Worker2 worker2)
- {
- Uow = uow;
- Worker1 = worker1;
- Worker2 = worker2;
- }
- }
-
- [Test]
- public void transient_scoped_Instance_is_built_once_per_resolution_to_the_Container()
- {
- var container = new Container(_ => { _.For<IUnitOfWork>().Use<DefaultUnitOfWork>(); });
-
- var cooridinator = container.GetInstance<WorkerCoordinator>();
-
- // The IUnitOfWork object instance is the same for
- // all the objects in the object graph that had
- // a constructor dependency on IUnitOfWork
- cooridinator.Uow
- .ShouldBeTheSameAs(cooridinator.Worker1.Uow);
-
- cooridinator.Uow
- .ShouldBeTheSameAs(cooridinator.Worker2.Uow);
-
- cooridinator.Worker1.Uow
- .ShouldBeTheSameAs(cooridinator.Worker2.Uow);
- }
-
-
-Very simply, using the AlwaysUnique means that a new object instance will be created every single time a configured Instance is either requested -from a Container or as a dependency to another object. The AlwaysUnique lifecycle is a "fire and forget" operation as the object instances are neither tracked nor disposed by StructureMap.
-
- [Test]
- public void Always_Unique()
- {
- var c = new Container(x => { x.For<IService>().Use<Service>().AlwaysUnique(); });
-
- // In a normal container, you get a new object
- // instance of the Service class in subsequent
- // requests
- c.GetInstance<IService>()
- .ShouldNotBeTheSameAs(c.GetInstance<IService>())
- .ShouldNotBeTheSameAs(c.GetInstance<IService>());
-
- // Within a nested container, 'Transient' now
- // means within the Nested Container.
- // A nested container is effectively one request
- using (var nested = c.GetNestedContainer())
- {
- nested.GetInstance<IService>()
- .ShouldNotBeTheSameAs(nested.GetInstance<IService>())
- .ShouldNotBeTheSameAs(nested.GetInstance<IService>());
- }
-
- // Even in a single request,
- var holder = c.GetInstance<ServiceUserHolder>();
- holder.Service.ShouldNotBeTheSameAs(holder.User.Service);
- }
-
-
-StructureMap 3.0 fixed the dreaded singletons with nested container's bug that was so problematic in 2.6.
-
- [Test]
- public void singletons()
- {
- var c = new Container(x => { x.For<IService>().Use<Service>().Singleton(); });
-
- // It's always the same object instance
- c.GetInstance<IService>()
- .ShouldBeTheSameAs(c.GetInstance<IService>())
- .ShouldBeTheSameAs(c.GetInstance<IService>())
- .ShouldBeTheSameAs(c.GetInstance<IService>())
- .ShouldBeTheSameAs(c.GetInstance<IService>())
- .ShouldBeTheSameAs(c.GetInstance<IService>());
- }
-
-
-Do note that objects created as the singleton scope will be disposed when the Container is disposed if they
-implement the IDisposable
interface:
- public interface IUnitOfWork
- {
- }
-
- public class DefaultUnitOfWork : IUnitOfWork
- {
- }
-
- public class Worker1
- {
- public IUnitOfWork Uow { get; set; }
-
- public Worker1(IUnitOfWork uow)
- {
- Uow = uow;
- }
- }
-
- public class Worker2
- {
- public IUnitOfWork Uow { get; set; }
-
- public Worker2(IUnitOfWork uow)
- {
- Uow = uow;
- }
- }
-
- public class WorkerCoordinator
- {
- public IUnitOfWork Uow { get; set; }
- public Worker1 Worker1 { get; set; }
- public Worker2 Worker2 { get; set; }
-
- public WorkerCoordinator(IUnitOfWork uow, Worker1 worker1, Worker2 worker2)
- {
- Uow = uow;
- Worker1 = worker1;
- Worker2 = worker2;
- }
- }
-
- [Test]
- public void transient_scoped_Instance_is_built_once_per_resolution_to_the_Container()
- {
- var container = new Container(_ => { _.For<IUnitOfWork>().Use<DefaultUnitOfWork>(); });
-
- var cooridinator = container.GetInstance<WorkerCoordinator>();
-
- // The IUnitOfWork object instance is the same for
- // all the objects in the object graph that had
- // a constructor dependency on IUnitOfWork
- cooridinator.Uow
- .ShouldBeTheSameAs(cooridinator.Worker1.Uow);
-
- cooridinator.Uow
- .ShouldBeTheSameAs(cooridinator.Worker2.Uow);
-
- cooridinator.Worker1.Uow
- .ShouldBeTheSameAs(cooridinator.Worker2.Uow);
- }
-
-
-The ThreadLocalStorage based lifecycle is seldom used, but the easiest example of using it and explanation is the integration test:
-
- [TestFixture]
- public class ThreadLocalStorageLifecycleTester
- {
- #region Setup/Teardown
-
- [SetUp]
- public void SetUp()
- {
- _lifecycle = new ThreadLocalStorageLifecycle();
-
- container = new Container(x => x.For<Rule>(Lifecycles.ThreadLocal).Use(() => new ColorRule("Red")));
- }
-
- #endregion
-
- private ThreadLocalStorageLifecycle _lifecycle;
- private ColorRule _rule1;
- private ColorRule _rule2;
- private ColorRule _rule3;
- private Container container;
-
-
- private void findRule1()
- {
- _rule1 = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
-
- var rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
- _rule1.ShouldBeTheSameAs(rule);
- }
-
- private void findRule2()
- {
- _rule2 = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
-
- var rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
- _rule2.ShouldBeTheSameAs(rule);
- }
-
- private void findRule3()
- {
- _rule3 = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
-
- var rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
- _rule3.ShouldBeTheSameAs(rule);
-
- rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
- _rule3.ShouldBeTheSameAs(rule);
-
- rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
- _rule3.ShouldBeTheSameAs(rule);
-
- rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
- _rule3.ShouldBeTheSameAs(rule);
- }
-
- [Test]
- public void object_has_been_created()
- {
- container.Model.For<Rule>().Default.ObjectHasBeenCreated().ShouldBeFalse();
- var r1 = container.GetInstance<Rule>();
- container.Model.For<Rule>().Default.ObjectHasBeenCreated().ShouldBeTrue();
- }
-
- [Test]
- public void FindUniqueInstancePerThread()
- {
- var t1 = new Thread(findRule1);
- var t2 = new Thread(findRule2);
- var t3 = new Thread(findRule3);
-
- t1.Start();
- t2.Start();
- t3.Start();
-
- t1.Join();
- t2.Join();
- t3.Join();
-
- _rule1.ShouldNotBeTheSameAs(_rule2);
- _rule1.ShouldNotBeTheSameAs(_rule3);
- _rule2.ShouldNotBeTheSameAs(_rule3);
- (_rule1.ID != _rule2.ID).ShouldBeTrue();
- (_rule1.ID != _rule3.ID).ShouldBeTrue();
- (_rule2.ID != _rule3.ID).ShouldBeTrue();
- }
- }
-
-
-In addition, the StructureMap.Web package adds the legacy ASP.Net related lifecycles for:
-Serializable
, not recommended but still present for legacy code
- public class AspNetRegistry : Registry
- {
- public AspNetRegistry()
- {
- For<IWeirdThing>().LifecycleIs<HttpContextLifecycle>();
- For<IGateway>().LifecycleIs<HybridLifecycle>();
- For<IRule>().LifecycleIs<HttpSessionLifecycle>();
- For<ICache>().LifecycleIs<HybridSessionLifecycle>();
- }
- }
-
-
-If you do use any of the HttpContext lifecycles, make sure you also do:
-
- HttpContextLifecycle.DisposeAndClearAll();
-
-at the end of your HTTP request.
- - -Out of the box, the core StructureMap assembly supports these lifecycles:
+Older versions of StructureMap referred to Transient as PerRequest, which might be a more accurate reflection of how this lifecycle behaves but
+causes some confusion with ASP.NET HTTP scoping. The easiest way to think of Transient is that a single object instance will be created for each top level
+call to Container.GetInstance()
(or any other object resolution method on the IContainer
interface). Transient objects resolved from a nested container, Transients are scoped to the lifecycle
+of the nested container itself. See Nested Containers (Per Request/Transaction) for more information.
StructureMap's behavior for transient objects that implement IDisposable
changed in 4.0 to introduce an "opt-in" tracking mode. Please see StructureMap and IDisposable for the details.
The following unit test demonstrates how Transient lifecycles work in both root and nested containers.
+
[Fact]
public void Transient()
{
var c = new Container(x => { x.For<IService>().Use<Service>().Transient(); });
// In a normal container, you get a new object
// instance of the Service class in subsequent
// requests
c.GetInstance<IService>()
.ShouldNotBeTheSameAs(c.GetInstance<IService>())
.ShouldNotBeTheSameAs(c.GetInstance<IService>());
// Within a nested container, 'Transient' now
// means within the Nested Container.
// A nested container is effectively one request
using (var nested = c.GetNestedContainer())
{
nested.GetInstance<IService>()
.ShouldBeTheSameAs(nested.GetInstance<IService>())
.ShouldBeTheSameAs(nested.GetInstance<IService>());
}
}
+Also note that a transient dependency will
+be created exactly once in an object graph resolved from IContainer.GetInstance(Type)
. Imagine that you are building an
+object graph with various objects that all need to apply some work to a shared unit of work object (think NHibernate's ISession, Entity Framework's DbContext, RavenDb's IDocumentSession):
public interface IUnitOfWork
{
}
public class DefaultUnitOfWork : IUnitOfWork
{
}
public class Worker1
{
public IUnitOfWork Uow { get; set; }
public Worker1(IUnitOfWork uow)
{
Uow = uow;
}
}
public class Worker2
{
public IUnitOfWork Uow { get; set; }
public Worker2(IUnitOfWork uow)
{
Uow = uow;
}
}
public class WorkerCoordinator
{
public IUnitOfWork Uow { get; set; }
public Worker1 Worker1 { get; set; }
public Worker2 Worker2 { get; set; }
public WorkerCoordinator(IUnitOfWork uow, Worker1 worker1, Worker2 worker2)
{
Uow = uow;
Worker1 = worker1;
Worker2 = worker2;
}
}
[Fact]
public void transient_scoped_Instance_is_built_once_per_resolution_to_the_Container()
{
var container = new Container(_ => { _.For<IUnitOfWork>().Use<DefaultUnitOfWork>(); });
var coordinator = container.GetInstance<WorkerCoordinator>();
// The IUnitOfWork object instance is the same for
// all the objects in the object graph that had
// a constructor dependency on IUnitOfWork
coordinator.Uow
.ShouldBeTheSameAs(coordinator.Worker1.Uow);
coordinator.Uow
.ShouldBeTheSameAs(coordinator.Worker2.Uow);
coordinator.Worker1.Uow
.ShouldBeTheSameAs(coordinator.Worker2.Uow);
}
+Very simply, using the AlwaysUnique means that a new object instance will be created every single time a configured Instance is either requested +from a Container or as a dependency to another object. The AlwaysUnique lifecycle is a "fire and forget" operation as the object instances are neither tracked nor disposed by StructureMap.
+
[Fact]
public void Always_Unique()
{
var c = new Container(x => { x.For<IService>().Use<Service>().AlwaysUnique(); });
// In a normal container, you get a new object
// instance of the Service class in subsequent
// requests
c.GetInstance<IService>()
.ShouldNotBeTheSameAs(c.GetInstance<IService>())
.ShouldNotBeTheSameAs(c.GetInstance<IService>());
// Within a nested container, 'Transient' now
// means within the Nested Container.
// A nested container is effectively one request
using (var nested = c.GetNestedContainer())
{
nested.GetInstance<IService>()
.ShouldNotBeTheSameAs(nested.GetInstance<IService>())
.ShouldNotBeTheSameAs(nested.GetInstance<IService>());
}
// Even in a single request,
var holder = c.GetInstance<ServiceUserHolder>();
holder.Service.ShouldNotBeTheSameAs(holder.User.Service);
}
+StructureMap 3.0 fixed the dreaded singletons with nested container's bug that was so problematic in 2.6.
+
[Fact]
public void singletons_are_disposed_when_the_container_is_disposed()
{
var container = new Container(_ =>
{
_.ForSingletonOf<DisposableSingleton>();
});
// As a singleton-scoped object, every request for DisposableSingleton
// will return the same object
var singleton = container.GetInstance<DisposableSingleton>();
singleton.ShouldBeSameAs(container.GetInstance<DisposableSingleton>());
singleton.ShouldBeSameAs(container.GetInstance<DisposableSingleton>());
singleton.ShouldBeSameAs(container.GetInstance<DisposableSingleton>());
singleton.ShouldBeSameAs(container.GetInstance<DisposableSingleton>());
singleton.WasDisposed.ShouldBeFalse();
// now, dispose the Container
container.Dispose();
// the SingletonThing scoped object should be disposed
singleton.WasDisposed.ShouldBeTrue();
}
+Do note that objects created as the singleton scope will be disposed when the Container is disposed if they
+implement the IDisposable
interface:
public interface IUnitOfWork
{
}
public class DefaultUnitOfWork : IUnitOfWork
{
}
public class Worker1
{
public IUnitOfWork Uow { get; set; }
public Worker1(IUnitOfWork uow)
{
Uow = uow;
}
}
public class Worker2
{
public IUnitOfWork Uow { get; set; }
public Worker2(IUnitOfWork uow)
{
Uow = uow;
}
}
public class WorkerCoordinator
{
public IUnitOfWork Uow { get; set; }
public Worker1 Worker1 { get; set; }
public Worker2 Worker2 { get; set; }
public WorkerCoordinator(IUnitOfWork uow, Worker1 worker1, Worker2 worker2)
{
Uow = uow;
Worker1 = worker1;
Worker2 = worker2;
}
}
[Fact]
public void transient_scoped_Instance_is_built_once_per_resolution_to_the_Container()
{
var container = new Container(_ => { _.For<IUnitOfWork>().Use<DefaultUnitOfWork>(); });
var coordinator = container.GetInstance<WorkerCoordinator>();
// The IUnitOfWork object instance is the same for
// all the objects in the object graph that had
// a constructor dependency on IUnitOfWork
coordinator.Uow
.ShouldBeTheSameAs(coordinator.Worker1.Uow);
coordinator.Uow
.ShouldBeTheSameAs(coordinator.Worker2.Uow);
coordinator.Worker1.Uow
.ShouldBeTheSameAs(coordinator.Worker2.Uow);
}
+New in StructureMap 4.0 is the ContainerScoped lifecycle that was designed specifically for compliance with the new ASP.Net DNX adapter model.
+ContainerScoped in this case means that a registration will be built once per Container
, such that the root container, any child or profile
+container, and every single nested container will build its own object instance.
The acceptance test for ContainerScoped
is shown below:
[Fact]
public void container_scoping_with_root_child_and_nested_container()
{
var container = new Container(_ =>
{
_.ForConcreteType<Disposable>().Configure.ContainerScoped();
});
var child = container.CreateChildContainer();
var nested = container.GetNestedContainer();
// Always the same object when requested from the root container
var mainDisposable = container.GetInstance<Disposable>();
mainDisposable
.ShouldBeTheSameAs(container.GetInstance<Disposable>());
// Always the same object when requested from a child container
var childDisposable = child.GetInstance<Disposable>();
childDisposable
.ShouldBeTheSameAs(child.GetInstance<Disposable>());
// Always the same object when requested from a nested container
var nestedDisposable = nested.GetInstance<Disposable>();
nestedDisposable
.ShouldBeTheSameAs(nested.GetInstance<Disposable>());
// It should be a different object instance for
// all three containers
mainDisposable
.ShouldNotBeTheSameAs(childDisposable);
mainDisposable
.ShouldNotBeTheSameAs(nestedDisposable);
childDisposable
.ShouldNotBeTheSameAs(nestedDisposable);
// When the nested container is disposed,
// it should dispose all the container scoped objects,
// but not impact the other containers
nested.Dispose();
nestedDisposable.WasDisposed.ShouldBeTrue();
childDisposable.WasDisposed.ShouldBeFalse();
mainDisposable.WasDisposed.ShouldBeFalse();
// Same for the child container
child.Dispose();
childDisposable.WasDisposed.ShouldBeTrue();
mainDisposable.WasDisposed.ShouldBeFalse();
// Same for the main container
container.Dispose();
mainDisposable.WasDisposed.ShouldBeTrue();
}
+The ThreadLocalStorage based lifecycle is seldom used, but the easiest example of using it and explanation is the integration test:
+
public class ThreadLocalStorageLifecycleTester
{
public ThreadLocalStorageLifecycleTester()
{
_lifecycle = new ThreadLocalStorageLifecycle();
container = new Container(x => x.For<Rule>(Lifecycles.ThreadLocal).Use(() => new ColorRule("Red")));
}
private ThreadLocalStorageLifecycle _lifecycle;
private ColorRule _rule1;
private ColorRule _rule2;
private ColorRule _rule3;
private Container container;
private void findRule1()
{
_rule1 = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
var rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
_rule1.ShouldBeTheSameAs(rule);
}
private void findRule2()
{
_rule2 = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
var rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
_rule2.ShouldBeTheSameAs(rule);
}
private void findRule3()
{
_rule3 = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
var rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
_rule3.ShouldBeTheSameAs(rule);
rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
_rule3.ShouldBeTheSameAs(rule);
rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
_rule3.ShouldBeTheSameAs(rule);
rule = container.GetInstance<Rule>().ShouldBeOfType<ColorRule>();
_rule3.ShouldBeTheSameAs(rule);
}
[Fact]
public void object_has_been_created()
{
container.Model.For<Rule>().Default.ObjectHasBeenCreated().ShouldBeFalse();
var r1 = container.GetInstance<Rule>();
container.Model.For<Rule>().Default.ObjectHasBeenCreated().ShouldBeTrue();
}
[Fact]
public void FindUniqueInstancePerThread()
{
var t1 = new Thread(findRule1);
var t2 = new Thread(findRule2);
var t3 = new Thread(findRule3);
t1.Start();
t2.Start();
t3.Start();
t1.Join();
t2.Join();
t3.Join();
_rule1.ShouldNotBeTheSameAs(_rule2);
_rule1.ShouldNotBeTheSameAs(_rule3);
_rule2.ShouldNotBeTheSameAs(_rule3);
(_rule1.ID != _rule2.ID).ShouldBeTrue();
(_rule1.ID != _rule3.ID).ShouldBeTrue();
(_rule2.ID != _rule3.ID).ShouldBeTrue();
}
}
+
+ The first thing you should know is that StructureMap (and other IoC tools like it) are designed to -make compositional and modular software designs easier to build by offloading the grubby mechanics of -resolving dependencies, reading configuration data, and assembling object graphs to the IoC tool instead -of cluttering up your application code.
-Before you get started with StructureMap it's recommended that you first get comfortable with the Software Design Concepts -of Dependency Injection -and Inversion Of Control. -It's important that you structure and build your application with these concepts in mind to fully utilize StructureMap's abilities.
-Assuming that you're already familiar with those concepts, or you'd really rather skip the pedantry and jump right into concrete code, the first thing to do is, go Get StructureMap and jump into usage.
-By and large, you really only do two kinds of things with StructureMap:
-Configure the container by registering the what and how StructureMap should build or find requested services based on a type and/or name.
-Resolve object instances of a service or dependency built out with all of its dependencies.
-So let's say that you have a simple object model like so:
-
- public interface IBar
- {
- }
-
- public class Bar : IBar
- {
- }
-
- public interface IFoo
- {
- }
-
- public class Foo : IFoo
- {
- public IBar Bar { get; private set; }
-
- public Foo(IBar bar)
- {
- Bar = bar;
- }
- }
-
-
-You could explicitly build a StructureMap Container
object to build these types like this:
-// Configure and build a brand new
-// StructureMap Container object
- var container = new Container(_ =>
- {
- _.For<IFoo>().Use<Foo>();
- _.For<IBar>().Use<Bar>();
- });
-
-// Now, resolve a new object instance of IFoo
- container.GetInstance<IFoo>()
- // should be type Foo
- .ShouldBeOfType<Foo>()
-
- // and the IBar dependency too
- .Bar.ShouldBeOfType<Foo>();
-
-
-
-or utilize StructureMap's type scanning conventions to configure the relationships and do the same thing like this:
-
- var container = new Container(_ =>
- {
- _.Scan(x =>
- {
- x.TheCallingAssembly();
- x.WithDefaultConventions();
- });
- });
-
- container.GetInstance<IFoo>()
- .ShouldBeOfType<Foo>()
- .Bar.ShouldBeOfType<Foo>();
-
-
-At some point you will want to integrate StructureMap into your application. Whether you are using Windows Presentation Foundation (WPF), FubuMVC, ASP.NET WebForms, ASP.NET MVC or any other framework or technology, you will have to do some sort of plumbing and bootstrapping. Depending on the used technology or framework there can be important integration points that you will have to use to fully enable the power of StructureMap.
-While StructureMap doesn't provide integration support out of the box for all of the frameworks and technologies out there, we do find it important to help you get started with integrating StructureMap into your application. That said, StructureMap does provide integration support for FubuMVC (a web framework, which is part of the same family as StructureMap).
-StructureMap, and any other IoC tool for that matter, is configuration intensive, which means that their will be problems in that configuration. We're all moving to more convention based type registration, so more stuff is happening off stage and out of your sight, making debugging the configuration even trickier. Not to worry (too much), StructureMap has some diagnostic abilities to help you solve configuration problems:
- -The first thing you should know is that StructureMap (and other IoC tools like it) are designed to +make compositional and modular software designs easier to build by offloading the grubby mechanics of +resolving dependencies, reading configuration data, and assembling object graphs to the IoC tool instead +of cluttering up your application code.
+Before you get started with StructureMap it's recommended that you first get comfortable with the Software Design Concepts +of Dependency Injection +and Inversion Of Control. +It's important that you structure and build your application with these concepts in mind to fully utilize StructureMap's abilities.
+Assuming that you're already familiar with those concepts, or you'd really rather skip the pedantry and jump right into concrete code, the first thing to do is, go Get StructureMap and jump into usage.
+By and large, you really only do two kinds of things with StructureMap:
+Configure the container by registering the what and how StructureMap should build or find requested services based on a type and/or name.
+Resolve object instances of a service or dependency built out with all of its dependencies.
+So let's say that you have a simple object model like so:
+
public interface IBar
{
}
public class Bar : IBar
{
}
public interface IFoo
{
}
public class Foo : IFoo
{
public IBar Bar { get; private set; }
public Foo(IBar bar)
{
Bar = bar;
}
}
+You could explicitly build a StructureMap Container
object to build these types like this:
// Configure and build a brand new
// StructureMap Container object
var container = new Container(_ =>
{
_.For<IFoo>().Use<Foo>();
_.For<IBar>().Use<Bar>();
});
// Now, resolve a new object instance of IFoo
container.GetInstance<IFoo>()
// should be type Foo
.ShouldBeOfType<Foo>()
// and the IBar dependency too
.Bar.ShouldBeOfType<Bar>();
+or utilize StructureMap's type scanning conventions to configure the relationships and do the same thing like this:
+
var container = new Container(_ =>
{
_.Scan(x =>
{
x.TheCallingAssembly();
x.WithDefaultConventions();
});
});
container.GetInstance<IFoo>()
.ShouldBeOfType<Foo>()
.Bar.ShouldBeOfType<Bar>();
+At some point you will want to integrate StructureMap into your application. Whether you are using Windows Presentation Foundation (WPF), FubuMVC, ASP.NET WebForms, ASP.NET MVC or any other framework or technology, you will have to do some sort of plumbing and bootstrapping. Depending on the used technology or framework there can be important integration points that you will have to use to fully enable the power of StructureMap.
+While StructureMap doesn't provide integration support out of the box for all of the frameworks and technologies out there, we do find it important to help you get started with integrating StructureMap into your application. That said, StructureMap does provide integration support for FubuMVC (a web framework, which is part of the same family as StructureMap).
+StructureMap, and any other IoC tool for that matter, is configuration intensive, which means that their will be problems in that configuration. We're all moving to more convention based type registration, so more stuff is happening off stage and out of your sight, making debugging the configuration even trickier. Not to worry (too much), StructureMap has some diagnostic abilities to help you solve configuration problems:
+ +In the early days of StructureMap we had several attributes for basic configuration that we'd just as soon +forget ever existed. Further more, the StructureMap strongly believes that the usage of StructureMap should +have as little impact on application code as possible -- and forcing users to spray .Net attributes all over +their own code is in clear violation of this philosophy. In other words, we don't want to be MEF.
+That being said, there are plenty of times when simple attribute usage is effective for one-off deviations from
+your normal registration conventions or cause less harm than having to constantly change a centralized Registry
or
+just seem more clear and understandable to users than a convention. For those usages, StructureMap 4.0 has introduced a
+new base class that can be extended and used to explicitly customize your StructureMap configuration:
public abstract class StructureMapAttribute : Attribute
{
public virtual void Alter(PluginFamily family)
{
}
public virtual void Alter(IConfiguredInstance instance)
{
}
public virtual void Alter(IConfiguredInstance instance, PropertyInfo property)
{
}
public virtual void Alter(IConfiguredInstance instance, ParameterInfo parameter)
{
}
}
+There's a couple thing to note, here about this new attibute:
+Take the new [Singleton]
attribute shown below:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
public class SingletonAttribute : StructureMapAttribute
{
// This method will affect the configuration for the
// entire plugin type
public override void Alter(PluginFamily family)
{
family.SetLifecycleTo<SingletonLifecycle>();
}
// This method will affect single registrations
public override void Alter(IConfiguredInstance instance)
{
instance.SetLifecycleTo<SingletonLifecycle>();
}
}
+This new attribute can be used on either the plugin type (typically an interface) or on a concrete type +to make an individual type registration be a singleton. You can see the usage on some types below:
+
[Singleton] // ALL Instance's of ITeamCache will be singletons by default
public interface ITeamCache { }
public class TeamCache : ITeamCache { }
public class OtherTeamCache : ITeamCache { }
public interface ITeam { }
public class Chargers : ITeam { }
[Singleton] // This specific type will be a singleton
public class Chiefs : ITeam { }
+As an example, let's say that you want a new attribute type that can decorate either properties or constructor parameters
+to say "use the value from the old .Net AppSettings collection as the value for this property/parameter." To build that new
+custom attribute, you would create a new attribute that subclasses StructureMapAttribute
and override the two methods shown below:
public class AppSettingAttribute : StructureMapAttribute
{
private readonly string _key;
public AppSettingAttribute(string key)
{
_key = key;
}
public override void Alter(IConfiguredInstance instance, PropertyInfo property)
{
var value = System.Configuration.ConfigurationManager.AppSettings[_key];
instance.Dependencies.AddForProperty(property, value);
}
public override void Alter(IConfiguredInstance instance, ParameterInfo parameter)
{
var value = System.Configuration.ConfigurationManager.AppSettings[_key];
instance.Dependencies.AddForConstructorParameter(parameter, value);
}
}
+To test out the new attribute above, say we have a concrete type like this one that we
+decorate with the new [AppSetting]
attribute:
public class AppSettingTarget
{
public string Name { get; set; }
[AppSetting("homestate")]
public string HomeState { get; set; }
public AppSettingTarget([AppSetting("name")]string name)
{
Name = name;
}
}
+The following unit test demonstrates our new custom [AppSetting]
attribute in action:
[Fact]
public void using_parameter_and_property_attibutes()
{
System.Configuration.ConfigurationManager.AppSettings["name"] = "Jeremy";
System.Configuration.ConfigurationManager.AppSettings["homestate"] = "Missouri";
System.Configuration.ConfigurationManager.AppSettings["name"].ShouldBe("Jeremy");
var container = new Container();
var target = container.GetInstance<AppSettingTarget>();
target.Name.ShouldBe("Jeremy");
target.HomeState.ShouldBe("Missouri");
Debug.WriteLine(container.Model.For<AppSettingTarget>().Default.DescribeBuildPlan());
}
+The build plan for AppSettingTarget
is determined by the active StructureMap
+container to be this:
+PluginType: StructureMap.Testing.Acceptance.attribute_usage+AppSettingTarget +Lifecycle: Transient +new AppSettingTarget(String name) + ┗ String name = Value: Jeremy +Set String HomeState = Value: Missouri ++
Note that the values retrieved from AppSettings
are essentially hard coded into the underlying builder function that StructureMap compiled for
+AppSettingTarget
. You could instead add a "lambda builder" dependency so that StructureMap had to
+use the live value for AppSettings
as it constructs objects.
StructureMap supplies a handful of built in attributes for customizing configuration:
+[ValidationMethod]
- Allows you to expose Environment Tests in your StructureMap registrations[SetterProperty]
- See Setter Injection[DefaultConstructor]
- Declare which constructor function should be used by StructureMap. See Constructor Selection for more information[AlwaysUnique]
and [Singleton]
- These attributes, new for StructureMap 4.0, just add another mechanism for lifecycle configurationStructureMap has rich support for registering types by scanning assemblies. -Between scanning and default conventions, configurations are often just a few -lines.
-One of the easiest ways to register types is by scanning the assembly your -registry is placed in.
-Note if you have other registries, StructureMap will not automatically -find them.
-
- [Test]
- public void scan_but_ignore_registries_by_default()
- {
- Scan(x => { x.TheCallingAssembly(); });
-
- TestingRegistry.WasUsed.ShouldBeFalse();
- }
-
-
-StructureMap can automatically include other registries with theLookForRegistries
-method.
- [Test]
- public void Search_for_registries_when_explicitly_told()
- {
- Scan(x =>
- {
- x.TheCallingAssembly();
- x.LookForRegistries();
- });
-
- TestingRegistry.WasUsed.ShouldBeTrue();
- }
-
-
-StructureMap provides facilities for registering types by path.
-
- [Test]
- public void scan_all_assemblies_in_a_folder()
- {
- Scan(x => x.AssembliesFromPath(assemblyScanningFolder));
- shouldHaveFamilyWithSameName<IInterfaceInWidget5>();
- shouldHaveFamilyWithSameName<IWorker>();
- }
-
- [Test]
- public void scan_all_assemblies_in_application_base_directory()
- {
- Scan(x => x.AssembliesFromApplicationBaseDirectory());
- shouldHaveFamilyWithSameName<IInterfaceInWidget5>();
- shouldHaveFamilyWithSameName<IWorker>();
- }
-
-
-StructureMap also makes it easy to exclude types, either individually or by namespace. -The following examples also show how StructureMap can register an assembly by providing -a type within that assembly.
-Excluding additional types or namespaces is as easy as calling the corresponding method -again.
-
- [Test]
- public void use_a_single_exclude_of_type()
- {
- Scan(x =>
- {
- x.AssemblyContainingType<ITypeThatHasAttributeButIsNotInRegistry>();
- x.ExcludeType<ITypeThatHasAttributeButIsNotInRegistry>();
- });
-
- shouldHaveFamily<IInterfaceInWidget5>();
- shouldNotHaveFamily<ITypeThatHasAttributeButIsNotInRegistry>();
- }
-
-
- [Test]
- public void use_a_single_exclude2()
- {
- Scan(x =>
- {
- x.AssemblyContainingType<ITypeThatHasAttributeButIsNotInRegistry>();
- x.ExcludeNamespace("StructureMap.Testing.Widget5");
- });
-
- shouldNotHaveFamily<IInterfaceInWidget5>();
- shouldNotHaveFamily<ITypeThatHasAttributeButIsNotInRegistry>();
- }
-
-
- [Test]
- public void use_a_single_exclude3()
- {
- Scan(x =>
- {
- x.AssemblyContainingType<ITypeThatHasAttributeButIsNotInRegistry>();
- x.ExcludeNamespaceContainingType<ITypeThatHasAttributeButIsNotInRegistry>();
- });
-
- shouldNotHaveFamily<IInterfaceInWidget5>();
- shouldNotHaveFamily<ITypeThatHasAttributeButIsNotInRegistry>();
- }
-
-
-It's just not possible (or desirable) for StructureMap to include every possible type of auto registration
-convention users might want, but that's okay because StructureMap allows you to create and use your own
-conventions through the IRegistrationConvention
interface:
- public interface IRegistrationConvention
- {
- void Process(Type type, Registry registry);
- }
-
-Let's say that you'd like a custom convention that just registers a concrete type against all the interfaces
-that it implements. You could then build a custom IRegistrationConvention
class like the following example:
- public interface IFoo
- {
- }
-
- public interface IBar
- {
- }
-
- public interface IBaz
- {
- }
-
- public class BusyGuy : IFoo, IBar, IBaz
- {
- }
-
- // Custom IRegistrationConvention
- public class AllInterfacesConvention : IRegistrationConvention
- {
- public void Process(Type type, Registry registry)
- {
- // Only work on concrete types
- if (!type.IsConcrete() || type.IsGenericType) return;
-
- // Register against all the interfaces implemented
- // by this concrete class
- type.GetInterfaces().Each(@interface => { registry.For(@interface).Use(type); });
- }
- }
-
- [Test]
- public void use_custom_registration_convention()
- {
- var container = new Container(_ =>
- {
- _.Scan(x =>
- {
- // You're probably going to want to tightly filter
- // the Type's that are applicable to avoid unwanted
- // registrations
- x.TheCallingAssembly();
- x.IncludeNamespaceContainingType<BusyGuy>();
-
- // Register the custom policy
- x.Convention<AllInterfacesConvention>();
- });
- });
-
- container.GetInstance<IFoo>().ShouldBeOfType<BusyGuy>();
- container.GetInstance<IBar>().ShouldBeOfType<BusyGuy>();
- container.GetInstance<IBaz>().ShouldBeOfType<BusyGuy>();
- }
-
-
-
-
- StructureMap has rich support for registering types by scanning assemblies and applying conventional registrations. +Between scanning and default conventions, configurations are often just a few +lines.
+Also see Type Scanning Diagnostics for help in understanding the assembly scanning behavior in your system.
+Assembly scanning operations are defined by the Registry.Scan()
method demonstrated below:
public class BasicScanning : Registry
{
public BasicScanning()
{
Scan(_ =>
{
// Declare which assemblies to scan
_.Assembly("StructureMap.Testing");
_.AssemblyContainingType<IWidget>();
// Filter types
_.Exclude(type => type.Name.Contains("Bad"));
// A custom registration convention
_.Convention<MySpecialRegistrationConvention>();
// Built in registration conventions
_.AddAllTypesOf<IWidget>().NameBy(x => x.Name.Replace("Widget", ""));
_.WithDefaultConventions();
});
}
}
+Please note (because I've been asked this several times over the years) that each call to Registry.Scan()
is an entirely atomic operation that has no impact on previous or subsequent calls.
Any given call to Registry.Scan()
consists of three different things:
One of the easiest ways to register types is by scanning the assembly your +registry is placed in.
+Note if you have other registries, StructureMap will not automatically +find them.
+
[Fact]
public void scan_but_ignore_registries_by_default()
{
Scan(x => { x.TheCallingAssembly(); });
TestingRegistry.WasUsed.ShouldBeFalse();
}
+Note that this method is an extension method in the StructureMap.Net4 assembly and cannot be used +if you target PCL compliance.
+StructureMap can automatically include other registries with theLookForRegistries
+method.
[Fact]
public void Search_for_registries_when_explicitly_told()
{
Scan(x =>
{
x.TheCallingAssembly();
x.LookForRegistries();
});
TestingRegistry.WasUsed.ShouldBeTrue();
}
+As of 4.0, this operation is now recursive and StructureMap has always been idempotent about adding Registry types
+StructureMap provides facilities for registering types by finding assemblies in the application bin path:
+
[Fact]
public void scan_all_assemblies_in_a_folder()
{
Scan(x => x.AssembliesFromPath(assemblyScanningFolder));
shouldHaveFamilyWithSameName<IInterfaceInWidget5>();
shouldHaveFamilyWithSameName<IWorker>();
shouldNotHaveFamilyWithSameName<IDefinedInExe>();
}
[Fact]
public void scan_all_assemblies_in_a_folder_with_path_filter()
{
Scan(x => x.AssembliesFromPath(assemblyScanningFolder, path => !path.Contains("Widget5")));
shouldNotHaveFamilyWithSameName<IInterfaceInWidget5>();
shouldHaveFamilyWithSameName<IWorker>();
shouldNotHaveFamilyWithSameName<IDefinedInExe>();
}
[Fact]
public void scan_all_assemblies_in_application_base_directory()
{
Scan(x => x.AssembliesFromApplicationBaseDirectory());
shouldHaveFamilyWithSameName<IInterfaceInWidget5>();
shouldHaveFamilyWithSameName<IWorker>();
shouldNotHaveFamilyWithSameName<IDefinedInExe>();
}
[Fact]
public void scan_all_assemblies_in_application_base_directory_with_path_filter()
{
Scan(x => x.AssembliesFromApplicationBaseDirectory(path => !path.Contains("Widget5")));
shouldNotHaveFamilyWithSameName<IInterfaceInWidget5>();
shouldHaveFamilyWithSameName<IWorker>();
shouldNotHaveFamilyWithSameName<IDefinedInExe>();
}
+Do note that StructureMap 4.0 does not search for .exe
files in the assembly search. The StructureMap team felt this was
+problematic and "nobody would ever actually want to do that." We were wrong, and due to many user requests, you can now
+opt in to scanning .exe
files with a new public method on AssemblyScanner
shown below:
[Fact]
public void scan_all_assemblies_in_a_folder_including_exe()
{
Scan(x => x.AssembliesAndExecutablesFromPath(assemblyScanningFolder));
shouldHaveFamilyWithSameName<IInterfaceInWidget5>();
shouldHaveFamilyWithSameName<IWorker>();
shouldHaveFamilyWithSameName<IDefinedInExe>();
}
[Fact]
public void scan_all_assemblies_in_a_folder_including_exe_with_path_filter()
{
Scan(x => x.AssembliesAndExecutablesFromPath(assemblyScanningFolder, path => !path.Contains("Widget5")));
shouldNotHaveFamilyWithSameName<IInterfaceInWidget5>();
shouldHaveFamilyWithSameName<IWorker>();
shouldHaveFamilyWithSameName<IDefinedInExe>();
}
[Fact]
public void scan_all_assemblies_in_application_base_directory_including_exe()
{
Scan(x => x.AssembliesAndExecutablesFromApplicationBaseDirectory());
shouldHaveFamilyWithSameName<IInterfaceInWidget5>();
shouldHaveFamilyWithSameName<IWorker>();
shouldHaveFamilyWithSameName<IDefinedInExe>();
}
[Fact]
public void scan_all_assemblies_in_application_base_directory_including_exe_with_path_filter()
{
Scan(x => x.AssembliesAndExecutablesFromApplicationBaseDirectory(path => !path.Contains("Widget5")));
shouldNotHaveFamilyWithSameName<IInterfaceInWidget5>();
shouldHaveFamilyWithSameName<IWorker>();
shouldHaveFamilyWithSameName<IDefinedInExe>();
}
+Do be aware that while this technique is very powerful for extensibility, it's been extremely problematic for +some folks in the past. The StructureMap team's recommendation for using this feature is to:
+Behind the scenes, StructureMap is using the Assembly.GetExportedTypes()
method from the .Net CLR to find types and this
+mechanism is very sensitive to missing dependencies. Again, thanks to the new type scanning diagnostics,
+you now have some visibility into assembly loading failures that used to be silently swallowed internally.
StructureMap also makes it easy to exclude types, either individually or by namespace. +The following examples also show how StructureMap can register an assembly by providing +a type within that assembly.
+Excluding additional types or namespaces is as easy as calling the corresponding method +again.
+
[Fact]
public void use_a_single_exclude_of_type()
{
Scan(x =>
{
x.AssemblyContainingType<ITypeThatHasAttributeButIsNotInRegistry>();
x.ExcludeType<ITypeThatHasAttributeButIsNotInRegistry>();
});
shouldHaveFamily<IInterfaceInWidget5>();
shouldNotHaveFamily<ITypeThatHasAttributeButIsNotInRegistry>();
}
[Fact]
public void use_a_single_exclude2()
{
Scan(x =>
{
x.AssemblyContainingType<ITypeThatHasAttributeButIsNotInRegistry>();
x.ExcludeNamespace("StructureMap.Testing.Widget5");
});
shouldNotHaveFamily<IInterfaceInWidget5>();
shouldNotHaveFamily<ITypeThatHasAttributeButIsNotInRegistry>();
}
[Fact]
public void use_a_single_exclude3()
{
Scan(x =>
{
x.AssemblyContainingType<ITypeThatHasAttributeButIsNotInRegistry>();
x.ExcludeNamespaceContainingType<ITypeThatHasAttributeButIsNotInRegistry>();
});
shouldNotHaveFamily<IInterfaceInWidget5>();
shouldNotHaveFamily<ITypeThatHasAttributeButIsNotInRegistry>();
}
+It's just not possible (or desirable) for StructureMap to include every possible type of auto registration
+convention users might want, but that's okay because StructureMap allows you to create and use your own
+conventions through the IRegistrationConvention
interface:
public interface IRegistrationConvention
{
void ScanTypes(TypeSet types, Registry registry);
}
+Let's say that you'd like a custom convention that just registers a concrete type against all the interfaces
+that it implements. You could then build a custom IRegistrationConvention
class like the following example:
public interface IFoo
{
}
public interface IBar
{
}
public interface IBaz
{
}
public class BusyGuy : IFoo, IBar, IBaz
{
}
// Custom IRegistrationConvention
public class AllInterfacesConvention : IRegistrationConvention
{
public void ScanTypes(TypeSet types, Registry registry)
{
// Only work on concrete types
types.FindTypes(TypeClassification.Concretes | TypeClassification.Closed).Each(type =>
{
// Register against all the interfaces implemented
// by this concrete class
type.GetInterfaces().Each(@interface => registry.For(@interface).Use(type));
});
}
}
[Fact]
public void use_custom_registration_convention()
{
var container = new Container(_ =>
{
_.Scan(x =>
{
// You're probably going to want to tightly filter
// the Type's that are applicable to avoid unwanted
// registrations
x.TheCallingAssembly();
x.IncludeNamespaceContainingType<BusyGuy>();
// Register the custom policy
x.Convention<AllInterfacesConvention>();
});
});
container.GetInstance<IFoo>().ShouldBeOfType<BusyGuy>();
container.GetInstance<IBar>().ShouldBeOfType<BusyGuy>();
container.GetInstance<IBaz>().ShouldBeOfType<BusyGuy>();
}
+Sometimes you need to have many implementations of an interface, and to have all of them used together, which usually involves creating another implementation of the interface which takes all the others as dependencies.
+If you try this in StructureMap, it will throw an exception as it detects a bi-directional dependency. This is because by default an IEnumerable<T>
constructor parameter will be populated with all instances of T, which would include the implementation with the IEnumerable<T>
parameter!
We can use a custom IRegistrationConvention
however to tell StructureMap that when it constructs a Composite, it should only include implementations which are not the Composite
:
public interface ISomething
{
IEnumerable<string> GetNames();
}
public class One : ISomething
{
public IEnumerable<string> GetNames() => new[] { "one" };
}
public class Two : ISomething
{
public IEnumerable<string> GetNames() => new[] { "two" };
}
public class SomethingComposite : ISomething
{
private readonly IEnumerable<ISomething> _others;
public SomethingComposite(IEnumerable<ISomething> others)
{
_others = others;
}
public IEnumerable<string> GetNames() => _others.SelectMany(other => other.GetNames());
}
// Custom IRegistrationConvention
public class CompositeDecorator<TComposite, TDependents> : IRegistrationConvention
where TComposite : TDependents
{
public void ScanTypes(TypeSet types, Registry registry)
{
var dependents = types
.FindTypes(TypeClassification.Concretes)
.Where(t => t.CanBeCastTo<TDependents>() && t.HasConstructors())
.Where(t => t != typeof(TComposite))
.ToList();
registry.For<TDependents>()
.Use<TComposite>()
.EnumerableOf<TDependents>().Contains(x => dependents.ForEach(t => x.Type(t)));
}
}
[Fact]
public void use_custom_registration_convention_2()
{
var container = new Container(_ =>
{
_.Scan(x =>
{
x.AssemblyContainingType<ISomething>();
x.Convention<CompositeDecorator<SomethingComposite, ISomething>>();
});
});
var composite = container.GetInstance<ISomething>();
composite.ShouldBeOfType<SomethingComposite>();
composite.GetNames().ShouldBe(new[] { "one", "two" }, ignoreOrder: true);
}
+The "default" convention simply tries to connect concrete classes to interfaces using +the I[Something]/[Something] naming convention as shown in this sample:
+
public interface ISpaceship { }
public class Spaceship : ISpaceship { }
public interface IRocket { }
public class Rocket : IRocket { }
[Fact]
public void default_scanning_in_action()
{
var container = new Container(_ =>
{
_.Scan(x =>
{
x.Assembly("StructureMap.Testing");
x.WithDefaultConventions();
});
});
container.GetInstance<ISpaceship>().ShouldBeOfType<Spaceship>();
container.GetInstance<IRocket>().ShouldBeOfType<Rocket>();
}
+The StructureMap team contains some VB6 veterans who hate Hungarian Notation, but can't shake the "I" nomenclature.
+To tell StructureMap to automatically register any interface that only has one concrete implementation, use this method:
+
public interface ISong { }
public class TheOnlySong : ISong { }
[Fact]
public void only_implementation()
{
var container = new Container(_ =>
{
_.Scan(x =>
{
x.TheCallingAssembly();
x.SingleImplementationsOfInterface();
});
});
container.GetInstance<ISong>()
.ShouldBeOfType<TheOnlySong>();
}
+To add all concrete types that can be cast to a named plugin type, use this syntax:
+
public interface IFantasySeries { }
public class WheelOfTime : IFantasySeries { }
public class GameOfThrones : IFantasySeries { }
public class BlackCompany : IFantasySeries { }
[Fact]
public void register_all_types_of_an_interface()
{
var container = new Container(_ =>
{
_.Scan(x =>
{
x.TheCallingAssembly();
x.AddAllTypesOf<IFantasySeries>();
// or
x.AddAllTypesOf(typeof(IFantasySeries))
.NameBy(type => type.Name.ToLower());
});
});
container.Model.For<IFantasySeries>()
.Instances.Select(x => x.ReturnedType)
.OrderBy(x => x.Name)
.ShouldHaveTheSameElementsAs(typeof(BlackCompany), typeof(GameOfThrones), typeof(WheelOfTime));
}
+Note, "T" does not have to be an interface, it's all based on the ability to cast a concrete type to the "T"
+See Generic Types for an example of using the ConnectImplementationsToTypesClosing
+mechanism for generic types.
The last built in registration convention is a mechanism to register all concrete types +that implement at least one interface against the first interface that they implement.
+
container = new Container(x =>
{
x.Scan(o =>
{
o.TheCallingAssembly();
o.RegisterConcreteTypesAgainstTheFirstInterface();
o.Exclude(t => t.CanBeCastTo(typeof(IGateway)));
});
});
+
+ If you need to add or change configuration to an existing StructureMap Container
object, you can use the IContainer.Configure()
method
-to add or change your container at runtime as shown below:
- [Test]
- public void change_default_in_an_existing_container()
- {
- var container = new Container(x => { x.For<IFoo>().Use<AFoo>(); });
-
- container.GetInstance<IFoo>().ShouldBeOfType<AFoo>();
-
- // Now, change the container configuration
- container.Configure(x => x.For<IFoo>().Use<BFoo>());
-
- // The default of IFoo is now different
- container.GetInstance<IFoo>().ShouldBeOfType<BFoo>();
-
- // or use the Inject method that's just syntactical
- // sugar for replacing the default of one type at a time
-
- container.Inject<IFoo>(new CFoo());
-
- container.GetInstance<IFoo>().ShouldBeOfType<CFoo>();
- }
-
-
-First off, the best advice on this functionality is don't use it outside of testing scenarios on the root container. The Configure()
method has to use a threading lock around the internal object model of a StructureMap container and can cause serious contention at runtime if you try to override services in the main application controller. Some frameworks (looking at you NancyFx) have abused this functionality quite badly in the past and the result was not pretty.
Registry
objects, then applying that Registry
to a container rather than repeatedly calling Configure()
Configure()
on the main application container after the initial configuration. Use nested or child containers that are not shared across threads or HTTP requests if you need to override services at runtimeConfigure()
at runtime because StructureMap has to recycle its internal Build Plan's based on
-the potential new configuration.If you need to add or change configuration to an existing StructureMap Container
object, you can use the IContainer.Configure()
method
+to add or change your container at runtime as shown below:
[Fact]
public void change_default_in_an_existing_container()
{
var container = new Container(x => { x.For<IFoo>().Use<AFoo>(); });
container.GetInstance<IFoo>().ShouldBeOfType<AFoo>();
// Now, change the container configuration
container.Configure(x => x.For<IFoo>().Use<BFoo>());
// The default of IFoo is now different
container.GetInstance<IFoo>().ShouldBeOfType<BFoo>();
// or use the Inject method that's just syntactical
// sugar for replacing the default of one type at a time
container.Inject<IFoo>(new CFoo());
container.GetInstance<IFoo>().ShouldBeOfType<CFoo>();
}
+First off, the best advice on this functionality is don't use it outside of testing scenarios on the root container. The Configure()
method has to use a threading lock around the internal object model of a StructureMap container and can cause serious contention at runtime if you try to override services in the main application controller. Some frameworks (looking at you NancyFx) have abused this functionality quite badly in the past and the result was not pretty.
Registry
objects, then applying that Registry
to a container rather than repeatedly calling Configure()
Configure()
on the main application container after the initial configuration. Use nested or child containers that are not shared across threads or HTTP requests if you need to override services at runtimeConfigure()
at runtime because StructureMap has to recycle its internal Build Plan's based on
+the potential new configuration.Several members of the StructureMap team were also very active in a now semi-defunct web framework called FubuMVC +that was built with quite a bit of extensibility in mind. One of the extensibility mechanisms that was successful in FubuMVC was the ability for applications or addon libraries to swap out the default services in the main StructureMap application container.
+The approach we took for this extensibility was what I flippantly call the "Mongolian BBQ" architecture. The framework should take the application specific registrations, the framework defaults, and all the discovered addons and figure out how to order the registrations to enforce the following levels of registration precedence:
+To make this kind of modular and adaptive registration work, FubuMVC introduced a couple concepts that we've now pulled back into StructureMap:
+Registry.For().ClearAll()
mechanism shown in this topic that tells StructureMap to "disregard what everyone else said to use".Typically in FubuMVC, we would use fallback service registrations for most of the framework defaults and occasionally use the ClearAll()
type mechanics down the line as an analogue to the CSS !important
keyword to make a particular registration take precedence in the face of multiple registrations.
In usage, let's say that our application needs some type of IWidget
service to run. For an important client, they want to deploy our system with
+a special version, so we will create a new StructureMap Registry
to apply their specific registrations using the ClearAll()
mechanism to
+insure that the important client gets their way:
public class ImportantClientWidget : IWidget { }
public class ImportantClientServices : Registry
{
public ImportantClientServices()
{
For<IWidget>().ClearAll().Use<ImportantClientWidget>();
}
}
+In usage, the ClearAll()
stomps all over the default registration before adding their own:
[Fact]
public void clear_all_in_action()
{
var container = new Container(_ =>
{
_.For<IWidget>().Use<AWidget>();
_.IncludeRegistry<ImportantClientServices>();
});
container.GetInstance<IWidget>()
.ShouldBeOfType<ImportantClientWidget>();
Debug.WriteLine(container.WhatDoIHave(pluginType: typeof(IWidget)));
}
+If you were to check the WhatDoIHave() view for IWidget
, you would see only the ImportantClientWidget
:
+============================================================================================================================================== +PluginType Namespace Lifecycle Description Name +---------------------------------------------------------------------------------------------------------------------------------------------- +IWidget StructureMap.Testing.Acceptance Transient StructureMap.Testing.Acceptance.clear_all+ImportantClientWidget (Default) +============================================================================================================================================== ++ +
The most common way for StructureMap to build or resolve a requested object is to build a concrete type directly by calling a
+public constructor function and optionally filling values in public setter properties. For this type of object construction,
+StructureMap exposes the IConfiguredInstance
interface as a means of querying and modifying how a concrete type will be
+created or resolved. While the Registry DSL fluent interface provides the main way of explicitly configuring concrete type creation,
+the IConfiguredInstance
interface is meant to support conventional registration,
+configuration attributes, and construction policies.
public interface IConfiguredInstance
{
string Name { get; set; }
Type PluggedType { get; }
DependencyCollection Dependencies { get; }
void AddInterceptor(IInterceptor interceptor);
void SetLifecycleTo<T>() where T : ILifecycle, new();
void SetLifecycleTo(ILifecycle lifecycle);
ILifecycle Lifecycle { get; }
ConstructorInfo Constructor { get; set; }
bool HasBuildPlan();
void ClearBuildPlan();
}
+You can override the lifecycle of a single IConfiguredInstance
by calling the LifecycleIs()
methods and either supplying a
+type of ILifecycle
or an ILifecycle
object. As a quick helper, there are also extension methods for common lifecycles:
IConfiguredInstance instance
= new ConfiguredInstance(typeof(WidgetHolder));
// Use the SingletonThing lifecycle
instance.Singleton();
// or supply an ILifecycle type
instance.SetLifecycleTo<ThreadLocalStorageLifecycle>();
// or supply an ILifecycle object
instance.SetLifecycleTo(new Lifecycles_Samples.MyCustomLifecycle());
// or override to the default "transient" lifecycle
instance.DefaultLifecycle();
+To find the constructor function parameters of an IConfiguredInstance
, just use this syntax (it's just .Net Reflection):
public class GuyWithArguments
{
public GuyWithArguments(IWidget widget, Rule rule)
{
}
}
[Fact]
public void reflecting_over_constructor_args()
{
IConfiguredInstance instance = new SmartInstance<GuyWithArguments>()
// I'm just forcing it to assign the constructor function
.SelectConstructor(() => new GuyWithArguments(null, null));
instance.Constructor.GetParameters().Select(x => x.Name)
.ShouldHaveTheSameElementsAs("widget", "rule");
}
+The constructor function selection process takes place as the very first step in creating a build plan and will be +available in any kind of construction policy or configuration attribute on +parameters or properties.
+There's a helper extension method off of `IConfiguredInstance' for finding all of the settable properties +that StructureMap can work with as shown below:
+
public class GuyWithProperties
{
public IWidget Widget { get; set; }
public Rule Rule { get; private set; }
}
[Fact]
public void get_settable_properties()
{
IConfiguredInstance instance
= new ConfiguredInstance(typeof(GuyWithProperties));
instance.SettableProperties()
.Single().Name.ShouldBe("Widget");
}
+The IConfiguredInstance.Dependencies
property is a collection of Argument
objects that model inline dependencies. A
+single Argument can refer to a public property or the parameter in a constructor function and consists of:
When StructureMap determines a build plan for a concrete type, it reflects over all the +parameters in the chosen constructor function and then the settable properties looking for any explicitly configured +dependencies by searching in order for:
+For primitive arguments like strings or numbers, the logic is to search first by name, then by type. All searching is done in
+the order that the Argument
objects are registered, so do watch the order in which you add arguments. There is a method to
+insert new arguments at the front of the list if you need to do any kind of overrides of previous behavior.
There are several Add()
overloads on IConfiguredInstance.Dependencies
to add dependencies, or you can use the two helper
+methods for constructor parameters and setter properties shown in the following sections.
If you already have a PropertyInfo
for the concrete type (like you might in a policy or attribute usage) and you want to register an inline dependency, there is the
+Dependencies.AddForProperty()
method as a convenience. For the actual value of the dependency, it needs to either be an object
+that can be cast to the property type or an Instance object that returns a type that can be cast to the property type.
With a value:
+
[Fact]
public void dependency_with_setter_with_value()
{
var instance
= new ConfiguredInstance(typeof(GuyWithProperties));
var prop = instance.PluggedType.GetProperty("Widget");
var myWidget = new ColorWidget("red");
instance.Dependencies.AddForProperty(prop, myWidget);
var container = new Container();
container.GetInstance<GuyWithProperties>(instance)
.Widget.ShouldBeTheSameAs(myWidget);
}
+With an Instance for the dependency value:
+
[Fact]
public void dependency_with_setter_with_instance()
{
var instance
= new ConfiguredInstance(typeof(GuyWithProperties));
var prop = instance.PluggedType.GetProperty("Widget");
var dependency = new SmartInstance<AWidget>();
instance.Dependencies.AddForProperty(prop, dependency);
var container = new Container();
container.GetInstance<GuyWithProperties>(instance)
.Widget.ShouldBeOfType<AWidget>();
}
+Likewise, you can add a dependency for a specific constructor parameter as either the actual value or an Instance object with the AddForConstructorParameter
helper method:
public class GuyWithDatabaseConnection
{
public string ConnectionString { get; set; }
public GuyWithDatabaseConnection(string connectionString)
{
ConnectionString = connectionString;
}
}
[Fact]
public void specify_dependency_by_constructor_parameter()
{
var instance = ConstructorInstance
.For<GuyWithDatabaseConnection>();
var parameter = instance.Constructor.GetParameters().Single();
parameter.Name.ShouldBe("connectionString");
var connString =
"I haven't used sql server in years and I don't remember what connection strings look like";
instance.Dependencies.AddForConstructorParameter(parameter, connString);
var guy = new Container().GetInstance<GuyWithDatabaseConnection>(instance);
guy.ConnectionString.ShouldBe(connString);
}
+You can add interceptors directly to a single IConfiguredInstance
with code like this:
public class SimpleWidget
{
public bool WasIntercepted = false;
public void Intercept()
{
WasIntercepted = true;
}
}
[Fact]
public void add_interceptor()
{
var interceptor =
new ActivatorInterceptor<SimpleWidget>(w => w.Intercept());
var instance = new SmartInstance<SimpleWidget>();
instance.AddInterceptor(interceptor);
new Container().GetInstance<SimpleWidget>(instance)
.WasIntercepted.ShouldBeTrue();
}
+See Interception and Decorators for more information.
+ +TODO(Write some content!)
- - -StructureMap 3.* greatly improves the control over the selection of constructor functions to build concrete types -by allowing users to override the constructor selection on specific Instance's and register custom rules for -selecting constructors to override the basic StructureMap behavior.
-If there are multiple public constructor functions on a concrete class, StructureMap's default behavior is to -select the "greediest" constructor, i.e., the constructor function with the most parameters. In the case of two or more -constructor functions with the same number of parameters StructureMap will simply take the first constructor encountered -in that subset of constructors.
-The default constructor selection is demonstrated below:
-
- public class GreaterThanRule : Rule
- {
- public string Attribute { get; set; }
- public int Value { get; set; }
-
- public GreaterThanRule()
- {
- }
-
- public GreaterThanRule(string attribute, int value)
- {
- Attribute = attribute;
- Value = value;
- }
- }
-
- [Test]
- public void using_the_greediest_ctor()
- {
- var container = new Container(_ =>
- {
- _.ForConcreteType<GreaterThanRule>().Configure
- .Ctor<string>("attribute").Is("foo")
- .Ctor<int>("value").Is(42);
- });
-
- var rule = container.GetInstance<GreaterThanRule>();
- rule.Attribute.ShouldBe("foo");
- rule.Value.ShouldBe(42);
- }
-
-
-To override the constructor selection explicitly on a case by case basis, you
-can use the SelectConstructor(Expression)
method in the Registry DSL
-as shown below:
- public class Thingie
- {
- public Thingie(IWidget widget)
- {
- CorrectCtorWasUsed = true;
- }
-
- public bool CorrectCtorWasUsed { get; set; }
-
- public Thingie(IWidget widget, IService service)
- {
- Assert.Fail("I should not have been called");
- }
- }
-
- [Test]
- public void override_the_constructor_selection()
- {
- var container = new Container(_ =>
- {
- _.For<IWidget>().Use<AWidget>();
-
- _.ForConcreteType<Thingie>().Configure
-
- // StructureMap parses the expression passed
- // into the method below to determine the
- // constructor
- .SelectConstructor(() => new Thingie(null));
- });
-
- container.GetInstance<Thingie>()
- .CorrectCtorWasUsed
- .ShouldBeTrue();
- }
-
-
-Alternatively, you can override the choice of constructor function by using the
-older [DefaultConstructor]
attribute like this:
- public class AttributedThing
- {
- // Normally the greediest ctor would be
- // selected, but using this attribute
- // will overrid that behavior
- [DefaultConstructor]
- public AttributedThing(IWidget widget)
- {
- CorrectCtorWasUsed = true;
- }
-
- public bool CorrectCtorWasUsed { get; set; }
-
- public AttributedThing(IWidget widget, IService service)
- {
- Assert.Fail("I should not have been called");
- }
- }
-
- [Test]
- public void select_constructor_by_attribute()
- {
- var container = new Container(_ => { _.For<IWidget>().Use<AWidget>(); });
-
- container.GetInstance<AttributedThing>()
- .CorrectCtorWasUsed
- .ShouldBeTrue();
- }
-
-
-If the constructor selection logic isn't what you want, you can systematically
-override the selection rules by registering one or more custom IConstructorSelector
-policies to a Container
. Do note that you can register more than one policy and they
-will be executed from last one registered to the first one registered.
Let's say that you want to control the constructor selection for all concrete -subclasses of an abstract class like this hiearchy:
-
- public abstract class BaseThing
- {
- public BaseThing(IWidget widget)
- {
- CorrectCtorWasUsed = true;
- }
-
- public bool CorrectCtorWasUsed { get; set; }
-
- public BaseThing(IWidget widget, IService service)
- {
- Assert.Fail("I should not have been called");
- }
- }
-
- public class Thing1 : BaseThing
- {
- public Thing1(IWidget widget) : base(widget)
- {
- }
-
- public Thing1(IWidget widget, IService service) : base(widget, service)
- {
- }
- }
-
- public class Thing2 : BaseThing
- {
- public Thing2(IWidget widget) : base(widget)
- {
- }
-
- public Thing2(IWidget widget, IService service) : base(widget, service)
- {
- }
- }
-
-
-You could create a custom IConstructorSelector
like this one below to override
-the constructor behavior for only subclasses of BaseThing
:
- public class ThingCtorRule : IConstructorSelector
- {
- public ConstructorInfo Find(Type pluggedType)
- {
- // if this rule does not apply to the pluggedType,
- // just return null to denote "not applicable"
- if (!pluggedType.CanBeCastTo<BaseThing>()) return null;
-
- return pluggedType.GetConstructor(new[] {typeof (IWidget)});
- }
- }
-
-
-Finally, you can register your custom rule as shown below:
-
- [Test]
- public void use_a_custom_constructor_selector()
- {
- var container = new Container(_ =>
- {
- _.For<IWidget>().Use<AWidget>();
-
- _.Policies.ConstructorSelector<ThingCtorRule>();
- });
-
- container.GetInstance<Thing1>()
- .CorrectCtorWasUsed.ShouldBeTrue();
-
- container.GetInstance<Thing2>()
- .CorrectCtorWasUsed.ShouldBeTrue();
- }
-
-
-
-
- StructureMap 3.* greatly improves the control over the selection of constructor functions to build concrete types +by allowing users to override the constructor selection on specific Instance's and register custom rules for +selecting constructors to override the basic StructureMap behavior.
+If there are multiple public constructor functions on a concrete class, StructureMap's default behavior is to +select the "greediest" constructor, i.e., the constructor function with the most parameters. In the case of two or more +constructor functions with the same number of parameters StructureMap will simply take the first constructor encountered +in that subset of constructors.
+The default constructor selection is demonstrated below:
+
public class GreaterThanRule : Rule
{
public string Attribute { get; set; }
public int Value { get; set; }
public GreaterThanRule()
{
}
public GreaterThanRule(string attribute, int value)
{
Attribute = attribute;
Value = value;
}
public GreaterThanRule(IWidget widget, Rule rule)
{
}
}
[Fact]
public void using_the_greediest_ctor()
{
var container = new Container(_ =>
{
_.ForConcreteType<GreaterThanRule>().Configure
.Ctor<string>("attribute").Is("foo")
.Ctor<int>("value").Is(42);
});
var rule = container.GetInstance<GreaterThanRule>();
rule.Attribute.ShouldBe("foo");
rule.Value.ShouldBe(42);
}
+New in StructureMap 4.0, the "greediest constructor selection" will bypass any constructor function that requires "simple" arguments +like strings, numbers, or enumeration values that are not explicitly configured for the instance.
+You can see this behavior shown below:
+
public class DbContext
{
public string ConnectionString { get; set; }
public DbContext(string connectionString)
{
ConnectionString = connectionString;
}
public DbContext() : this("default value")
{
}
}
[Fact]
public void should_bypass_ctor_with_unresolvable_simple_args()
{
var container = new Container();
container.GetInstance<DbContext>()
.ConnectionString.ShouldBe("default value");
}
[Fact]
public void should_use_greediest_ctor_that_has_all_of_simple_dependencies()
{
var container = new Container(_ =>
{
_.ForConcreteType<DbContext>().Configure
.Ctor<string>("connectionString").Is("not the default");
});
container.GetInstance<DbContext>()
.ConnectionString.ShouldBe("not the default");
}
+To override the constructor selection explicitly on a case by case basis, you
+can use the SelectConstructor(Expression)
method in the Registry DSL
+as shown below:
public class Thingie
{
public Thingie(IWidget widget)
{
CorrectCtorWasUsed = true;
}
public bool CorrectCtorWasUsed { get; set; }
public Thingie(IWidget widget, IService service)
{
Assert.True(false, "I should not have been called");
}
}
[Fact]
public void override_the_constructor_selection()
{
var container = new Container(_ =>
{
_.For<IWidget>().Use<AWidget>();
_.ForConcreteType<Thingie>().Configure
// StructureMap parses the expression passed
// into the method below to determine the
// constructor
.SelectConstructor(() => new Thingie(null));
});
container.GetInstance<Thingie>()
.CorrectCtorWasUsed
.ShouldBeTrue();
}
+Alternatively, you can override the choice of constructor function by using the
+older [DefaultConstructor]
attribute like this:
public class AttributedThing
{
// Normally the greediest ctor would be
// selected, but using this attribute
// will overrid that behavior
[DefaultConstructor]
public AttributedThing(IWidget widget)
{
CorrectCtorWasUsed = true;
}
public bool CorrectCtorWasUsed { get; set; }
public AttributedThing(IWidget widget, IService service)
{
Assert.True(false, "I should not have been called");
}
}
[Fact]
public void select_constructor_by_attribute()
{
var container = new Container(_ => { _.For<IWidget>().Use<AWidget>(); });
container.GetInstance<AttributedThing>()
.CorrectCtorWasUsed
.ShouldBeTrue();
}
+If the constructor selection logic isn't what you want, you can systematically
+override the selection rules by registering one or more custom IConstructorSelector
+policies to a Container
. Do note that you can register more than one policy and they
+will be executed from last one registered to the first one registered.
Let's say that you want to control the constructor selection for all concrete +subclasses of an abstract class like this hiearchy:
+
public abstract class BaseThing
{
public BaseThing(IWidget widget)
{
CorrectCtorWasUsed = true;
}
public bool CorrectCtorWasUsed { get; set; }
public BaseThing(IWidget widget, IService service)
{
Assert.True(false, "I should not have been called");
}
}
public class Thing1 : BaseThing
{
public Thing1(IWidget widget) : base(widget)
{
}
public Thing1(IWidget widget, IService service) : base(widget, service)
{
}
}
public class Thing2 : BaseThing
{
public Thing2(IWidget widget) : base(widget)
{
}
public Thing2(IWidget widget, IService service) : base(widget, service)
{
}
}
+You could create a custom IConstructorSelector
like this one below to override
+the constructor behavior for only subclasses of BaseThing
:
public class ThingCtorRule : IConstructorSelector
{
public ConstructorInfo Find(Type pluggedType, DependencyCollection dependencies, PluginGraph graph)
{
// if this rule does not apply to the pluggedType,
// just return null to denote "not applicable"
if (!pluggedType.CanBeCastTo<BaseThing>()) return null;
return pluggedType.GetConstructor(new[] { typeof(IWidget) });
}
}
+Finally, you can register your custom rule as shown below:
+
[Fact]
public void use_a_custom_constructor_selector()
{
var container = new Container(_ =>
{
_.For<IWidget>().Use<AWidget>();
_.Policies.ConstructorSelector<ThingCtorRule>();
});
container.GetInstance<Thing1>()
.CorrectCtorWasUsed.ShouldBeTrue();
container.GetInstance<Thing2>()
.CorrectCtorWasUsed.ShouldBeTrue();
}
+
+ It's frequently common to register existing objects with a StructureMap Container
and there are
+overloads of the Registry.For().Use(object)
and Registry.For().Add(object)
methods to do just that:
[Fact]
public void should_be_able_to_resolve_from_the_generic_family_expression()
{
var widget = new AWidget();
var container = new Container(x => x.For(typeof(IWidget)).Use(widget).Named("mine"));
container.GetInstance<IWidget>("mine").ShouldBeTheSameAs(widget);
}
+Injecting an existing object into the Container
makes it a de facto singleton, but the Container
treats it with a
+special scope called ObjectLifecycle
if you happen to look into the WhatDoIHave() diagnostics.
StructureMap will attempt to call the IDisposable.Dispose()
on any objects that are directly injected into a Container
+that implement IDisposable
when the Container
itself is disposed.
The following is a technique that was stolen from FubuMVC where we used
+the idea of default or "fallback" registrations to make it mechanically simple for the core framework to declare
+the default service registrations in the Container
for what FubuMVC needed while allowing applications to happily
+override specific registrations without having to worry about the order in which the registrations were done.
To see this in practice, say you have an application that will support client specific modularity that might allow
+business clients to override the base StructureMap registrations. This is a perfect use case for
+defining the application defaults with UseIfNone()
as shown in this example below:
public class DefaultServices : Registry
{
public DefaultServices()
{
// If nobody else provides a default
// for IWidget, use AWidget
For<IWidget>().UseIfNone<AWidget>();
}
}
public class SpecificServices : Registry
{
public SpecificServices()
{
// Use BWidget for IWidget, period
For<IWidget>().Use<BWidget>();
}
}
+In application usage, you would add the default UseIfNone()
registrations, and optionally pick
+up additional extension Registry
objects from extension assemblies as shown in this example:
[AttributeUsage(AttributeTargets.Assembly)]
public class ProductModuleAttribute : Attribute
{
}
public class ApplicationRegistry : Registry
{
public ApplicationRegistry()
{
// Use the default services as fallbacks
IncludeRegistry<DefaultServices>();
// Dependending on what assemblies are present,
// this might find specific registrations that
// will take precedence over the UseIfNone()
// registrations in DefaultServices
Scan(_ =>
{
_.AssembliesFromApplicationBaseDirectory(
assem => assem.HasAttribute<ProductModuleAttribute>());
_.LookForRegistries();
});
}
}
[Fact]
public void see_use_if_none_in_action()
{
var container1 = Container.For<DefaultServices>();
// No other registrations, so fallback
// to AWidget
container1.GetInstance<IWidget>()
.ShouldBeOfType<AWidget>();
var container2 = new Container(_ =>
{
// add both registries above
// NOTE: the order does not matter for IWidget
_.IncludeRegistry<SpecificServices>();
_.IncludeRegistry<DefaultServices>();
});
// The registration in SpecificServices
// should win out
container2.GetInstance<IWidget>()
.ShouldBeOfType<BWidget>();
}
+
+ TODO(Write some content!)
- + -As of the 3.0 release, StructureMap provides a streamlined fluent interface called the Registry DSL to configure a StructureMap -Container with both explicit registrations and conventional auto-registrations. StructureMap no longer supports Xml configuration or MEF-style attribute configuration -- but there is some facility for rolling your own attribute-based configuration support.
-ObjectFactory
wrapper for Container is still available in 3.0, but we strongly recommend against using it for new applications. It only exists for easier compatibility with older installations.The first step in using StructureMap is configuring a Container
object. The following examples are based on the usage of the Registry DSL.
Let's say that you have a simple set of services like this:
-
- public interface IBar
- {
- }
-
- public class Bar : IBar
- {
- }
-
- public interface IFoo
- {
- }
-
- public class Foo : IFoo
- {
- public IBar Bar { get; private set; }
-
- public Foo(IBar bar)
- {
- Bar = bar;
- }
- }
-
-
-A simple configuration of a StructureMap Container might then be:
-
-// Example #1 - Create an container instance and directly pass in the configuration.
- var container1 = new Container(c =>
- {
- c.For<IFoo>().Use<Foo>();
- c.For<IBar>().Use<Bar>();
- });
-
-// Example #2 - Create an container instance but add configuration later.
- var container2 = new Container();
-
- container2.Configure(c =>
- {
- c.For<IFoo>().Use<Foo>();
- c.For<IBar>().Use<Bar>();
- });
-
-// Example #3 - Initialize the static ObjectFactory container.
-// NOTE: ObjectFactory has been deprecated and will be removed
-// in a future 4.0 release
- ObjectFactory.Initialize(i =>
- {
- i.For<IFoo>().Use<Foo>();
- i.For<IBar>().Use<Bar>();
- });
-
-Initializing or configuring the container is usually done at application startup and is located as close as possible to the application's entry point. -This place is sometimes referred to as the composition root of the application. -In our example we are composing our application's object graph by connecting abstractions to concrete types.
-We are using the fluent API For<TInterface>().Use<TConcrete>()
which registers a default instance for a given plugin type (the TInterface type in this case). In our example we want an new instance of Foo
every time we request the abstraction IFoo
.
The recommended way of using the Registry DSL is by defining one or more Registry
classes. Typically, you would subclass the Registry
class,
-then use the Fluent API methods exposed by the Registry
class to describe a Container
configuration.
Here's a sample Registry
class used to configure the same types as in our previous example:
- public class FooBarRegistry : Registry
- {
- public FooBarRegistry()
- {
- For<IFoo>().Use<Foo>();
- For<IBar>().Use<Bar>();
- }
- }
-
-
-When you set up a Container
, you need to simply direct the Container
to use the configuration in that Registry
class.
-// Example #1
- var container1 = new Container(new FooBarRegistry());
-
-// Example #2
- var container2 = new Container(c => { c.AddRegistry<FooBarRegistry>(); });
-
-// Example #3 -- create a container for a single Registry
- var container3 = Container.For<FooBarRegistry>();
-
-In real world applications you also have to deal with repetitive similar registrations. Such registrations are tedious, easy to forget and can be a weak spot in your application. StructureMap provides Auto-Registration and Conventions which mitigates this pain and eases the maintenance burden. StructureMap exposes this feature through the Registry DSL by the Scan
method.
In our example there is an reoccuring pattern, we are connecting the plugin type ISomething
to a concrete type Something
, meaning IFoo
to Foo
and IBar
to Bar
. Wouldn't it be cool if we could write a convention for exactly doing that? Fortunatly StructureMap has already one build in. Let's see how we can create an container with the same configuration as in the above examples.
-// Example #1
- var container1 = new Container(c =>
- c.Scan(scanner =>
- {
- scanner.TheCallingAssembly();
- scanner.WithDefaultConventions();
- }));
-
-// Example #2
- var container2 = new Container();
-
- container2.Configure(c =>
- c.Scan(scanner =>
- {
- scanner.TheCallingAssembly();
- scanner.WithDefaultConventions();
- }));
-
-
-
-We instruct the scanner to scan through the calling assembly with default conventions on. This wil find and registers the default instance for IFoo
and IBar
which are obviously the concrete types Foo
and Bar
. Now whenever you add an additional interface IMoreFoo
and a class MoreFoo
to your application's code base, it's automatically picked up by the scanner.
Sometimes classes need to be suplied with some primitive value in its constructor. For example the System.Data.SqlClient.SqlConnection
needs to be supplied with the connection string in its constructor. No problem, just set up the value of the constructor argument in the bootstrapping:
- var container = new Container(c =>
- {
- //just for demo purposes, normally you don't want to embed the connection string directly into code.
- c.For<IDbConnection>().Use<SqlConnection>().Ctor<string>().Is("YOUR_CONNECTION_STRING");
- //a better way would be providing a delegate that retrieves the value from your app config.
- });
-
-So far you have seen an couple of ways to work with the <linkto:registration/registry-dsl]> and configure an Container
object or ObjectFactory
. We have seen examples of configuration that allows us to build objects that doesn't depend on anything like the Bar
class, or do depend on other types like the Foo
class needs an instance of IBar
. In our last example we have seen configuration for objects that needs some primitive types like strings in its constructor function.
As of the 3.0 release, StructureMap provides a streamlined fluent interface called the Registry DSL to configure a StructureMap +Container with both explicit registrations and conventional auto-registrations. StructureMap no longer supports Xml configuration or MEF-style attribute configuration -- but there is some facility for rolling your own attribute-based configuration support.
+The first step in using StructureMap is configuring a Container
object. The following examples are based on the usage of the Registry DSL.
Let's say that you have a simple set of services like this:
+
public interface IBar
{
}
public class Bar : IBar
{
}
public interface IFoo
{
}
public class Foo : IFoo
{
public IBar Bar { get; private set; }
public Foo(IBar bar)
{
Bar = bar;
}
}
+A simple configuration of a StructureMap Container might then be:
+
// Example #1 - Create an container instance and directly pass in the configuration.
var container1 = new Container(c =>
{
c.For<IFoo>().Use<Foo>();
c.For<IBar>().Use<Bar>();
});
// Example #2 - Create an container instance but add configuration later.
var container2 = new Container();
container2.Configure(c =>
{
c.For<IFoo>().Use<Foo>();
c.For<IBar>().Use<Bar>();
});
+Initializing or configuring the container is usually done at application startup and is located as close as possible to the application's entry point. +This place is sometimes referred to as the composition root of the application. +In our example we are composing our application's object graph by connecting abstractions to concrete types.
+We are using the fluent API For<TInterface>().Use<TConcrete>()
which registers a default instance for a given plugin type (the TInterface type in this case). In our example we want an new instance of Foo
every time we request the abstraction IFoo
.
The recommended way of using the Registry DSL is by defining one or more Registry
classes. Typically, you would subclass the Registry
class,
+then use the Fluent API methods exposed by the Registry
class to describe a Container
configuration.
Here's a sample Registry
class used to configure the same types as in our previous example:
public class FooBarRegistry : Registry
{
public FooBarRegistry()
{
For<IFoo>().Use<Foo>();
For<IBar>().Use<Bar>();
}
}
+When you set up a Container
, you need to simply direct the Container
to use the configuration in that Registry
class.
// Example #1
var container1 = new Container(new FooBarRegistry());
// Example #2
var container2 = new Container(c => { c.AddRegistry<FooBarRegistry>(); });
// Example #3 -- create a container for a single Registry
var container3 = Container.For<FooBarRegistry>();
+In real world applications you also have to deal with repetitive similar registrations. Such registrations are tedious, easy to forget and can be a weak spot in your application. StructureMap provides Auto-Registration and Conventions which mitigates this pain and eases the maintenance burden. StructureMap exposes this feature through the Registry DSL by the Scan
method.
In our example there is an reoccuring pattern, we are connecting the plugin type ISomething
to a concrete type Something
, meaning IFoo
to Foo
and IBar
to Bar
. Wouldn't it be cool if we could write a convention for exactly doing that? Fortunatly StructureMap has already one build in. Let's see how we can create an container with the same configuration as in the above examples.
// Example #1
var container1 = new Container(c =>
c.Scan(scanner =>
{
scanner.TheCallingAssembly();
scanner.WithDefaultConventions();
}));
// Example #2
var container2 = new Container();
container2.Configure(c =>
c.Scan(scanner =>
{
scanner.TheCallingAssembly();
scanner.WithDefaultConventions();
}));
+We instruct the scanner to scan through the calling assembly with default conventions on. This will find and register the default instance for IFoo
and IBar
which are obviously the concrete types Foo
and Bar
. Now whenever you add an additional interface IMoreFoo
and a class MoreFoo
to your application's code base, it's automatically picked up by the scanner.
Sometimes classes need to be supplied with some primitive value in its constructor. For example the System.Data.SqlClient.SqlConnection
needs to be supplied with the connection string in its constructor. No problem, just set up the value of the constructor argument in the bootstrapping:
var container = new Container(c =>
{
//just for demo purposes, normally you don't want to embed the connection string directly into code.
c.For<IDbConnection>().Use<SqlConnection>().Ctor<string>().Is("YOUR_CONNECTION_STRING");
//a better way would be providing a delegate that retrieves the value from your app config.
});
+So far you have seen an couple of ways to work with the Registry DSL and configure a Container
object. We have seen examples of configuration that allow us to build objects that don't depend on anything like the Bar
class, or do depend on other types like the Foo
class needs an instance of IBar
. In our last example we have seen configuration for objects that need some primitive types like strings in its constructor function.
Changing Configuration at Runtime
-While you generally allow StructureMap to just use auto-wiring to fill the dependencies of a concrete type, there are times -when you may want to explicitly configure individual dependencies on a case by case basis. In the case of primitive types -like strings or numbers, StructureMap will not do any auto-wiring, so it's incumbent upon you the user to supply the dependency.
-Let's say we have a simple class called ColorWidget
like the following:
- public class ColorWidget : IWidget
- {
- public string Color { get; set; }
-
- public ColorWidget(string color)
- {
- Color = color;
- }
- }
-
-
-To register the ColorWidget
, you would supply the value of the color
parameter to the constructor function like so:
- [Test]
- public void inline_usage_of_primitive_constructor_argument()
- {
- var container = new Container(_ =>
- {
- _.For<IWidget>().Use<ColorWidget>()
- .Ctor<string>().Is("Red");
- });
-
- container.GetInstance<IWidget>()
- .ShouldBeOfType<ColorWidget>()
- .Color.ShouldBe("Red");
- }
-
-
-The ability to explicitly define dependencies inline isn't commonly used these days, but was actually one of the very core use cases in the initial versions of StructureMap. One of the first usages of StructureMap in a production application was in a configurable rules engine using an Event-Condition-Action architecture where the conditions and actions were configured in StructureMap as inline dependencies of Rule objects. Using StructureMap's old Xml configuration, we could define rules for new customers by registering rule objects with the container that reused existing condition and action classes in new configurations.
-To make that concrete and establish a sample problem domain, consider these types:
-
- public class SomeEvent
- {
- }
-
- public interface ICondition
- {
- bool Matches(SomeEvent @event);
- }
-
- public interface IAction
- {
- void PerformWork(SomeEvent @event);
- }
-
- public interface IEventRule
- {
- void ProcessEvent(SomeEvent @event);
- }
-
-
-Now, let's move on to seeing how we could use inline dependency configuration to register new rules.
-First off, let's say that we have a SimpleRule
that takes a single condition and action:
- public class SimpleRule : IEventRule
- {
- private readonly ICondition _condition;
- private readonly IAction _action;
-
- public SimpleRule(ICondition condition, IAction action)
- {
- _condition = condition;
- _action = action;
- }
-
- public void ProcessEvent(SomeEvent @event)
- {
- if (_condition.Matches(@event))
- {
- _action.PerformWork(@event);
- }
- }
- }
-
-
-Now, since SimpleRule
has only a single dependency on both IAction
and ICondition
, we can create new rules by registering new Instance's
-of SimpleRule
with different combinations of its dependencies:
- public class InlineCtorArgs : Registry
- {
- public InlineCtorArgs()
- {
- // Defining args by type
- For<IEventRule>().Use<SimpleRule>()
- .Ctor<ICondition>().Is<Condition1>()
- .Ctor<IAction>().Is<Action1>()
- .Named("One");
-
- // Pass the explicit values for dependencies
- For<IEventRule>().Use<SimpleRule>()
- .Ctor<ICondition>().Is(new Condition2())
- .Ctor<IAction>().Is(new Action2())
- .Named("Two");
-
- // Use Lambda construction
- For<IEventRule>().Use<SimpleRule>()
- .Ctor<ICondition>().Is(() => new Condition3())
- .Ctor<IAction>().Is("some crazy builder", c => c.GetInstance<Action3>())
- .Named("Three");
-
- // Rarely used, but gives you a "do any crazy thing" option
- // Pass in your own Instance object
- For<IEventRule>().Use<SimpleRule>()
- .Ctor<IAction>().Is(new MySpecialActionInstance());
-
- // Inline configuration of your dependency's dependencies
-
- For<IEventRule>().Use<SimpleRule>()
- .Ctor<ICondition>().IsSpecial(_ => _.Type<BigCondition>().Ctor<int>().Is(100))
-
- // or
- .Ctor<ICondition>().Is(new SmartInstance<BigCondition>().Ctor<int>().Is(100));
- }
-
- public class BigCondition : ICondition
- {
- public BigCondition(int number)
- {
- }
-
- public bool Matches(SomeEvent @event)
- {
- throw new NotImplementedException();
- }
- }
-
- public class MySpecialActionInstance : LambdaInstance<Action3>
- {
- public MySpecialActionInstance()
- : base(() => new Action3())
- {
- }
- }
- }
-
-
-The inline dependency configuration using the Ctor<T>().Is()
syntax supports all the common StructureMap configuration options: define by type, by lambdas, by value, or if you really want to risk severe eye strain, you can use your own Instance objects and define the configuration of your dependency's dependencies.
If for some reason you need to specify an inline constructor argument dependency, and the concrete type has more than one dependency for that type, -you just need to specify the parameter name as shown in this sample:
-
- public class DualConditionRule : IEventRule
- {
- private readonly ICondition _first;
- private readonly ICondition _second;
- private readonly IAction _action;
-
- public DualConditionRule(ICondition first, ICondition second, IAction action)
- {
- _first = first;
- _second = second;
- _action = action;
- }
-
- public void ProcessEvent(SomeEvent @event)
- {
- if (_first.Matches(@event) || _second.Matches(@event))
- {
- _action.PerformWork(@event);
- }
- }
- }
-
- public class DualConditionRuleRegistry : Registry
- {
- public DualConditionRuleRegistry()
- {
- // In this case, because DualConditionRule
- // has two different
- For<IEventRule>().Use<DualConditionRule>()
- .Ctor<ICondition>("first").Is<Condition1>()
- .Ctor<ICondition>("second").Is<Condition2>();
- }
- }
-
-
-You can also configure setter dependencies with a similar syntax, but with additional options to specify the property name
-by using an Expression
as shown below:
- public class RuleWithSetters : IEventRule
- {
- public ICondition Condition { get; set; }
- public IAction Action { get; set; }
-
- public void ProcessEvent(SomeEvent @event)
- {
- if (Condition.Matches(@event))
- {
- Action.PerformWork(@event);
- }
- }
- }
-
- public class RuleWithSettersRegistry : Registry
- {
- public RuleWithSettersRegistry()
- {
- For<IEventRule>().Use<RuleWithSetters>()
- .Setter<ICondition>().Is<Condition1>()
-
- // or
- .Setter(x => x.Action).Is(new Action1())
-
- // or if you need to specify the name
- .Setter<IAction>("Action").Is<Action2>()
-
- // or you can configure values *after* the object
- // is constructed with the SetProperty method
- .SetProperty(x => x.Action = new Action2());
- }
- }
-
-
-TODO(show a sample of using enumerable dependencies)
-In some cases, you may want to skip the Registry DSL and go straight for the raw dependencies structures. Let's say that -we're using an open generic type for our rules engine so that we can respond to multiple event types:
-
- public interface IEventRule<TEvent>
- {
- void ProcessEvent(TEvent @event);
- }
-
- public interface ICondition<TEvent>
- {
- bool Matches(TEvent @event);
- }
-
- public class Condition1<TEvent> : ICondition<TEvent>
- {
- public bool Matches(TEvent @event)
- {
- throw new NotImplementedException();
- }
- }
-
- public interface IAction<TEvent>
- {
- void PerformWork(TEvent @event);
- }
-
- public class Action1<TEvent> : IAction<TEvent>
- {
- public void PerformWork(TEvent @event)
- {
- throw new NotImplementedException();
- }
- }
-
- public class EventRule<TEvent> : IEventRule<TEvent>
- {
- private readonly string _name;
- private readonly ICondition<TEvent> _condition;
- private readonly IAction<TEvent> _action;
-
- public EventRule(string name, ICondition<TEvent> condition, IAction<TEvent> action)
- {
- _name = name;
- _condition = condition;
- _action = action;
- }
-
- public string Name
- {
- get { return _name; }
- }
-
- public void ProcessEvent(TEvent @event)
- {
- if (_condition.Matches(@event))
- {
- _action.PerformWork(@event);
- }
- }
- }
-
-
-As an alternative approach, we could build up ConstructorInstance
objects to represent our rules like so:
- public class OpenTypesRegistry : Registry
- {
- public OpenTypesRegistry()
- {
- var instance = new ConstructorInstance(typeof (EventRule<>));
-
- // By name
- instance.Dependencies.Add("action", typeof (Action1<>));
-
- // Everything else is syntactical sugur over this:
- instance.Dependencies.Add(new Argument
- {
- Type = typeof (IAction<>), // The dependency type
- Name = "action", // The name of the dependency, either
- // a constructor argument name or
- // the name of a setter property
-
- // Specify the actual dependency
- // This can be either a concrete type, the prebuilt value,
- // or an Instance
- Dependency = typeof (Action1<>)
- });
- }
- }
-
-
-It's frequently useful to explicitly configure all the elements for an enumerable argument (arrays, IEnumerable, or IList). -StructureMap provides this syntax to do just that:
-
- public class BigRule : IEventRule
- {
- private readonly IEnumerable<ICondition> _conditions;
- private readonly IEnumerable<IAction> _actions;
-
- public BigRule(IEnumerable<ICondition> conditions, IEnumerable<IAction> actions)
- {
- _conditions = conditions;
- _actions = actions;
- }
-
- public void ProcessEvent(SomeEvent @event)
- {
- if (_conditions.Any(x => x.Matches(@event)))
- {
- _actions.Each(x => x.PerformWork(@event));
- }
- }
- }
-
- public class BigRuleRegistry : Registry
- {
- public BigRuleRegistry()
- {
- For<IEventRule>().Use<BigRule>()
-
- // Each line in the nested closure adds another
- // ICondition to the enumerable dependency in
- // the order in which they are configured
- .EnumerableOf<ICondition>().Contains(_ =>
- {
- _.Type<Condition1>();
- _.Type<Condition2>();
- })
- .EnumerableOf<IAction>().Contains(_ =>
- {
- _.Type<Action1>();
- _.Object(new Action2());
- });
- }
- }
-
-
-
-
- While you generally allow StructureMap to just use auto-wiring to fill the dependencies of a concrete type, there are times +when you may want to explicitly configure individual dependencies on a case by case basis. In the case of primitive types +like strings or numbers, StructureMap will not do any auto-wiring, so it's incumbent upon you the user to supply the dependency.
+Let's say we have a simple class called ColorWidget
like the following:
public class ColorWidget : IWidget
{
public string Color { get; set; }
public ColorWidget(string color)
{
Color = color;
}
}
+To register the ColorWidget
, you would supply the value of the color
parameter to the constructor function like so:
[Fact]
public void inline_usage_of_primitive_constructor_argument()
{
var container = new Container(_ =>
{
_.For<IWidget>().Use<ColorWidget>()
.Ctor<string>().Is("Red");
});
container.GetInstance<IWidget>()
.ShouldBeOfType<ColorWidget>()
.Color.ShouldBe("Red");
}
+The ability to explicitly define dependencies inline isn't commonly used these days, but was actually one of the very core use cases in the initial versions of StructureMap. One of the first usages of StructureMap in a production application was in a configurable rules engine using an Event-Condition-Action architecture where the conditions and actions were configured in StructureMap as inline dependencies of Rule objects. Using StructureMap's old Xml configuration, we could define rules for new customers by registering rule objects with the container that reused existing condition and action classes in new configurations.
+To make that concrete and establish a sample problem domain, consider these types:
+
public class SomeEvent
{
}
public interface ICondition
{
bool Matches(SomeEvent @event);
}
public interface IAction
{
void PerformWork(SomeEvent @event);
}
public interface IEventRule
{
void ProcessEvent(SomeEvent @event);
}
+Now, let's move on to seeing how we could use inline dependency configuration to register new rules.
+First off, let's say that we have a SimpleRule
that takes a single condition and action:
public class SimpleRule : IEventRule
{
private readonly ICondition _condition;
private readonly IAction _action;
public SimpleRule(ICondition condition, IAction action)
{
_condition = condition;
_action = action;
}
public void ProcessEvent(SomeEvent @event)
{
if (_condition.Matches(@event))
{
_action.PerformWork(@event);
}
}
}
+Now, since SimpleRule
has only a single dependency on both IAction
and ICondition
, we can create new rules by registering new Instance's
+of SimpleRule
with different combinations of its dependencies:
public class InlineCtorArgs : Registry
{
public InlineCtorArgs()
{
// Defining args by type
For<IEventRule>().Use<SimpleRule>()
.Ctor<ICondition>().Is<Condition1>()
.Ctor<IAction>().Is<Action1>()
.Named("One");
// Pass the explicit values for dependencies
For<IEventRule>().Use<SimpleRule>()
.Ctor<ICondition>().Is(new Condition2())
.Ctor<IAction>().Is(new Action2())
.Named("Two");
// Use Lambda construction
For<IEventRule>().Use<SimpleRule>()
.Ctor<ICondition>().Is(() => new Condition3())
.Ctor<IAction>().Is("some crazy builder", c => c.GetInstance<Action3>())
.Named("Three");
// Rarely used, but gives you a "do any crazy thing" option
// Pass in your own Instance object
For<IEventRule>().Use<SimpleRule>()
.Ctor<IAction>().Is(new MySpecialActionInstance());
// Inline configuration of your dependency's dependencies
For<IEventRule>().Use<SimpleRule>()
.Ctor<ICondition>().IsSpecial(_ => _.Type<BigCondition>().Ctor<int>().Is(100))
// or
.Ctor<ICondition>().Is(new SmartInstance<BigCondition>().Ctor<int>().Is(100));
}
public class BigCondition : ICondition
{
public BigCondition(int number)
{
}
public bool Matches(SomeEvent @event)
{
throw new NotImplementedException();
}
}
public class MySpecialActionInstance : LambdaInstance<Action3>
{
public MySpecialActionInstance()
: base(() => new Action3())
{
}
}
}
+The inline dependency configuration using the Ctor<T>().Is()
syntax supports all the common StructureMap configuration options: define by type, by lambdas, by value, or if you really want to risk severe eye strain, you can use your own Instance objects and define the configuration of your dependency's dependencies.
If for some reason you need to specify an inline constructor argument dependency, and the concrete type has more than one dependency for that type, +you just need to specify the parameter name as shown in this sample:
+
public class DualConditionRule : IEventRule
{
private readonly ICondition _first;
private readonly ICondition _second;
private readonly IAction _action;
public DualConditionRule(ICondition first, ICondition second, IAction action)
{
_first = first;
_second = second;
_action = action;
}
public void ProcessEvent(SomeEvent @event)
{
if (_first.Matches(@event) || _second.Matches(@event))
{
_action.PerformWork(@event);
}
}
}
public class DualConditionRuleRegistry : Registry
{
public DualConditionRuleRegistry()
{
// In this case, because DualConditionRule
// has two different
For<IEventRule>().Use<DualConditionRule>()
.Ctor<ICondition>("first").Is<Condition1>()
.Ctor<ICondition>("second").Is<Condition2>();
}
}
+You can also configure setter dependencies with a similar syntax, but with additional options to specify the property name
+by using an Expression
as shown below:
public class RuleWithSetters : IEventRule
{
public ICondition Condition { get; set; }
public IAction Action { get; set; }
public void ProcessEvent(SomeEvent @event)
{
if (Condition.Matches(@event))
{
Action.PerformWork(@event);
}
}
}
public class RuleWithSettersRegistry : Registry
{
public RuleWithSettersRegistry()
{
For<IEventRule>().Use<RuleWithSetters>()
.Setter<ICondition>().Is<Condition1>()
// or
.Setter(x => x.Action).Is(new Action1())
// or if you need to specify the name
.Setter<IAction>("Action").Is<Action2>()
// or you can configure values *after* the object
// is constructed with the SetProperty method
.SetProperty(x => x.Action = new Action2());
}
}
+TODO(show a sample of using enumerable dependencies)
+In some cases, you may want to skip the Registry DSL and go straight for the raw dependencies structures. Let's say that +we're using an open generic type for our rules engine so that we can respond to multiple event types:
+
public interface IEventRule<TEvent>
{
void ProcessEvent(TEvent @event);
}
public interface ICondition<TEvent>
{
bool Matches(TEvent @event);
}
public class Condition1<TEvent> : ICondition<TEvent>
{
public bool Matches(TEvent @event)
{
throw new NotImplementedException();
}
}
public interface IAction<TEvent>
{
void PerformWork(TEvent @event);
}
public class Action1<TEvent> : IAction<TEvent>
{
public void PerformWork(TEvent @event)
{
throw new NotImplementedException();
}
}
public class EventRule<TEvent> : IEventRule<TEvent>
{
private readonly string _name;
private readonly ICondition<TEvent> _condition;
private readonly IAction<TEvent> _action;
public EventRule(string name, ICondition<TEvent> condition, IAction<TEvent> action)
{
_name = name;
_condition = condition;
_action = action;
}
public string Name
{
get { return _name; }
}
public void ProcessEvent(TEvent @event)
{
if (_condition.Matches(@event))
{
_action.PerformWork(@event);
}
}
}
+As an alternative approach, we could build up ConstructorInstance
objects to represent our rules like so:
public class OpenTypesRegistry : Registry
{
public OpenTypesRegistry()
{
var instance = new ConstructorInstance(typeof(EventRule<>));
// By name
instance.Dependencies.Add("action", typeof(Action1<>));
// Everything else is syntactical sugur over this:
instance.Dependencies.Add(new Argument
{
Type = typeof(IAction<>), // The dependency type
Name = "action", // The name of the dependency, either
// a constructor argument name or
// the name of a setter property
// Specify the actual dependency
// This can be either a concrete type, the prebuilt value,
// or an Instance
Dependency = typeof(Action1<>)
});
}
}
+It's frequently useful to explicitly configure all the elements for an enumerable argument (arrays, IEnumerable, or IList). +StructureMap provides this syntax to do just that:
+
public class BigRule : IEventRule
{
private readonly IEnumerable<ICondition> _conditions;
private readonly IEnumerable<IAction> _actions;
public BigRule(IEnumerable<ICondition> conditions, IEnumerable<IAction> actions)
{
_conditions = conditions;
_actions = actions;
}
public void ProcessEvent(SomeEvent @event)
{
if (_conditions.Any(x => x.Matches(@event)))
{
_actions.Each(x => x.PerformWork(@event));
}
}
}
public class BigRuleRegistry : Registry
{
public BigRuleRegistry()
{
For<IEventRule>().Use<BigRule>()
// Each line in the nested closure adds another
// ICondition to the enumerable dependency in
// the order in which they are configured
.EnumerableOf<ICondition>().Contains(_ =>
{
_.Type<Condition1>();
_.Type<Condition2>();
})
.EnumerableOf<IAction>().Contains(_ =>
{
_.Type<Action1>();
_.Object(new Action2());
});
}
}
+
+ New for StructureMap 3.0 is a feature to create missing service registrations at runtime based on pluggable rules using the new IFamilyPolicy
-interface:
-
- /// <summary>
- /// Allows StructureMap to fill in missing registrations by unknown plugin types
- /// at runtime
- /// </summary>
- public interface IFamilyPolicy
- {
- /// <summary>
- /// Allows you to create missing registrations for an unknown plugin type
- /// at runtime.
- /// Return null if this policy does not apply to the given type
- /// </summary>
- PluginFamily Build(Type type);
-
- /// <summary>
- /// Should this policy be used to determine whether or not the Container has
- /// registrations for a plugin type in the PluginGraph.HasFamily(type) method
- /// </summary>
- bool AppliesToHasFamilyChecks { get; }
- }
-
-Internally, if you make a request to IContainer.GetInstance(type)
for a type that the active Container
does not recognize, StructureMap will next
-try to apply all the registered IFamilyPolicy
policies to create a PluginFamily
object for that plugin type that models the registrations for that plugin type, including the default, additional named instances, interceptors or decorators, and lifecycle rules.
The simplest built in example is the EnumerableFamilyPolicy
shown below that can fill in requests for IList<T>
, ICollection<T>
, and T[]
with a collection of all the known registrations of the type T
:
- public class EnumerableFamilyPolicy : IFamilyPolicy
- {
- public PluginFamily Build(Type type)
- {
- if (EnumerableInstance.IsEnumerable(type))
- {
- var family = new PluginFamily(type);
- family.SetDefault(new AllPossibleInstance(type));
-
- return family;
- }
-
- return null;
- }
-
- public bool AppliesToHasFamilyChecks
- {
- get
- {
- return false;
- }
-
- }
- }
-
-The result of EnumerableFamilyPolicy
in action is shown by the acceptance test below:
- [Test]
- public void collection_types_are_all_possible_by_default()
- {
- // NOTE that we do NOT make any explicit registration of
- // IList<IWidget>, IEnumerable<IWidget>, ICollection<IWidget>, or IWidget[]
- var container = new Container(_ =>
- {
- _.For<IWidget>().Add<AWidget>();
- _.For<IWidget>().Add<BWidget>();
- _.For<IWidget>().Add<CWidget>();
- });
-
- // IList<T>
- container.GetInstance<IList<IWidget>>()
- .Select(x => x.GetType())
- .ShouldHaveTheSameElementsAs(typeof (AWidget), typeof (BWidget), typeof (CWidget));
-
- // ICollection<T>
- container.GetInstance<ICollection<IWidget>>()
- .Select(x => x.GetType())
- .ShouldHaveTheSameElementsAs(typeof (AWidget), typeof (BWidget), typeof (CWidget));
-
- // Array of T
- container.GetInstance<IWidget[]>()
- .Select(x => x.GetType())
- .ShouldHaveTheSameElementsAs(typeof (AWidget), typeof (BWidget), typeof (CWidget));
- }
-
-
-See also the Handling Missing Named Instances for runtime determination of named instances within a known plugin type.
-StructureMap and StructureMap.AutoMocking use several IFamilyPolicy
rules internally to create default behavior. In all cases, any custom
-IFamilyPolicy
rule that you explicitly add to a Container
will be evaluated before the built in policies.
Func<string, T>
builders.FubuMVC 2.0 (still unreleased to the public as of yet, but in production usage) uses a custom family policy in its StructureMap -integration to auto-resolve concrete configuration types like the following type:
-
- public class SomeSettings
- {
- public string ThisDirectory { get; set; }
- public string ThatDirectory { get; set; }
- }
-
-
-Unless the system using this object has explicitly registered SomeSettings
, we want StructureMap to resolve this object by
-using data from the basic .Net appSettings collection to create a SomeSettings
object.
For the sake of the example, assume that you have a functioning service that implements this interface below:
-
- public interface ISettingsProvider
- {
- T SettingsFor<T>() where T : class, new();
-
- object SettingsFor(Type settingsType);
- }
-
- public class AppSettingsProvider : ISettingsProvider
- {
- public T SettingsFor<T>() where T : class, new()
- {
- return SettingsFor(typeof (T)).As<T>();
- }
-
- public object SettingsFor(Type settingsType)
- {
- // The real one reads key/value data from
- // the appSettings and uses FubuCore's
- // model binding to assign data to a new
- // object of settingsType
- return null;
- }
- }
-
-
-Assuming that ISettingsProvider
is registered in your StructureMap Container
, you could then craft a custom
-IFamilyPolicy
class like this:
- public class SettingPolicy : IFamilyPolicy
- {
- public PluginFamily Build(Type type)
- {
- if (type.Name.EndsWith("Settings") && type.IsConcreteWithDefaultCtor())
- {
- var family = new PluginFamily(type);
- var instance = buildInstanceForType(type);
- family.SetDefault(instance);
-
- return family;
- }
-
- return null;
- }
-
- public bool AppliesToHasFamilyChecks
- {
- get { return true; }
- }
-
-
- private static Instance buildInstanceForType(Type type)
- {
- var instanceType = typeof (SettingsInstance<>).MakeGenericType(type);
- var instance = Activator.CreateInstance(instanceType).As<Instance>();
- return instance;
- }
- }
-
- // SettingsInstance just uses the registered service for ISettingsProvider to
- // build the real object
- public class SettingsInstance<T> : LambdaInstance<T> where T : class, new()
- {
- public SettingsInstance() : base("Building {0} from application settings".ToFormat(typeof (T).FullName),
- c => c.GetInstance<ISettingsProvider>().SettingsFor<T>())
- {
- }
- }
-
-
-SettingPolicy
is able to create a registration on the fly for any concrete type whose name ends in "Settings" and has a default, no arg
-constructor.
To use register the custom SettingPolicy
, use one of the Registry.Policies.OnMissingFamily()
methods:
- public class SettingsRegistry : Registry
- {
- public SettingsRegistry()
- {
- For<ISettingsProvider>().Use<AppSettingsProvider>();
- Policies.OnMissingFamily<SettingPolicy>();
- }
- }
-
-
-You can see the real implementation of the SettingPolicy
in action in its integration tests on GitHub.
New for StructureMap 3.0 is a feature to create missing service registrations at runtime based on pluggable rules using the new IFamilyPolicy
+interface:
public interface IFamilyPolicy
{
PluginFamily Build(Type type);
bool AppliesToHasFamilyChecks { get; }
}
+Internally, if you make a request to IContainer.GetInstance(type)
for a type that the active Container
does not recognize, StructureMap will next
+try to apply all the registered IFamilyPolicy
policies to create a PluginFamily
object for that plugin type that models the registrations for that plugin type, including the default, additional named instances, interceptors or decorators, and lifecycle rules.
The simplest built in example is the EnumerableFamilyPolicy
shown below that can fill in requests for IList<T>
, ICollection<T>
, and T[]
with a collection of all the known registrations of the type T
:
public class EnumerableFamilyPolicy : IFamilyPolicy
{
public PluginFamily Build(Type type)
{
if (EnumerableInstance.IsEnumerable(type))
{
var family = new PluginFamily(type);
family.SetDefault(new AllPossibleInstance(type));
return family;
}
return null;
}
public bool AppliesToHasFamilyChecks
{
get
{
return false;
}
}
}
+The result of EnumerableFamilyPolicy
in action is shown by the acceptance test below:
[Fact]
public void collection_types_are_all_possible_by_default()
{
// NOTE that we do NOT make any explicit registration of
// IList<IWidget>, IEnumerable<IWidget>, ICollection<IWidget>, or IWidget[]
var container = new Container(_ =>
{
_.For<IWidget>().Add<AWidget>();
_.For<IWidget>().Add<BWidget>();
_.For<IWidget>().Add<CWidget>();
});
// IList<T>
container.GetInstance<IList<IWidget>>()
.Select(x => x.GetType())
.ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));
// ICollection<T>
container.GetInstance<ICollection<IWidget>>()
.Select(x => x.GetType())
.ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));
// Array of T
container.GetInstance<IWidget[]>()
.Select(x => x.GetType())
.ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));
}
+See also the Handling Missing Named Instances for runtime determination of named instances within a known plugin type.
+StructureMap and StructureMap.AutoMocking use several IFamilyPolicy
rules internally to create default behavior. In all cases, any custom
+IFamilyPolicy
rule that you explicitly add to a Container
will be evaluated before the built in policies.
Func<string, T>
builders.FubuMVC 2.0 (still unreleased to the public as of yet, but in production usage) uses a custom family policy in its StructureMap +integration to auto-resolve concrete configuration types like the following type:
+
public class SomeSettings
{
public string ThisDirectory { get; set; }
public string ThatDirectory { get; set; }
}
+Unless the system using this object has explicitly registered SomeSettings
, we want StructureMap to resolve this object by
+using data from the basic .Net appSettings collection to create a SomeSettings
object.
For the sake of the example, assume that you have a functioning service that implements this interface below:
+
public interface ISettingsProvider
{
T SettingsFor<T>() where T : class, new();
object SettingsFor(Type settingsType);
}
public class AppSettingsProvider : ISettingsProvider
{
public T SettingsFor<T>() where T : class, new()
{
return SettingsFor(typeof (T)).As<T>();
}
public object SettingsFor(Type settingsType)
{
// The real one reads key/value data from
// the appSettings and uses FubuCore's
// model binding to assign data to a new
// object of settingsType
return null;
}
}
+Assuming that ISettingsProvider
is registered in your StructureMap Container
, you could then craft a custom
+IFamilyPolicy
class like this:
public class SettingPolicy : IFamilyPolicy
{
public PluginFamily Build(Type type)
{
if (type.Name.EndsWith("Settings") && type.IsConcreteWithDefaultCtor())
{
var family = new PluginFamily(type);
var instance = buildInstanceForType(type);
family.SetDefault(instance);
return family;
}
return null;
}
public bool AppliesToHasFamilyChecks
{
get { return true; }
}
private static Instance buildInstanceForType(Type type)
{
var instanceType = typeof (SettingsInstance<>).MakeGenericType(type);
var instance = Activator.CreateInstance(instanceType).As<Instance>();
return instance;
}
}
// SettingsInstance just uses the registered service for ISettingsProvider to
// build the real object
public class SettingsInstance<T> : LambdaInstance<T> where T : class, new()
{
public SettingsInstance() : base("Building {0} from application settings".ToFormat(typeof (T).FullName),
c => c.GetInstance<ISettingsProvider>().SettingsFor<T>())
{
}
}
+SettingPolicy
is able to create a registration on the fly for any concrete type whose name ends in "Settings" and has a default, no arg
+constructor.
To use register the custom SettingPolicy
, use one of the Registry.Policies.OnMissingFamily()
methods:
public class SettingsRegistry : Registry
{
public SettingsRegistry()
{
For<ISettingsProvider>().Use<AppSettingsProvider>();
Policies.OnMissingFamily<SettingPolicy>();
}
}
+You can see the real implementation of the SettingPolicy
in action in its integration tests on GitHub.
StructureMap has long supported conventional policies for registration based on type scanning
+and 3.0 introduced cleaner mechanisms for interception policies.
+The 4.0 release extends StructureMap's support for conventional build policies with a new mechanism for altering
+how object instances are built based on user created meta-conventions using the IInstancePolicy
shown below:
public interface IInstancePolicy
{
void Apply(Type pluginType, Instance instance);
}
+These policies are registered as part of the registry dsl with
+the Policies.Add()
method:
var container = new Container(_ =>
{
_.Policies.Add<MyCustomPolicy>();
// or
_.Policies.Add(new MyCustomPolicy());
});
+The IInstancePolicy
mechanism probably works differently than other IoC containers in that the policy
+is applied to the container's underlying configuration model instead of at runtime. Internally, StructureMap lazily creates
+a "build plan" for each configured Instance at the first time
+that that Instance is built or resolved. As part of creating that build plan, StructureMap runs
+all the registered IInstancePolicy
objects against the Instance in question to capture any
+potential changes before "baking" the build plan into a .Net Expression
that is then compiled into a Func
+for actual construction.
The Instance
objects will give you access to the types being created, the configured name of the Instance (if any),
+the ability to add interceptors and to modify the lifecycle. If you wish to add inline dependencies to
+Instances that are built by calling constructor function and setter properties, you may find it easier
+to use the ConfiguredInstancePolicy
base class as a convenience:
public abstract class ConfiguredInstancePolicy : IInstancePolicy
{
public void Apply(Type pluginType, Instance instance)
{
var configured = instance as IConfiguredInstance;
if (configured != null)
{
apply(pluginType, configured);
}
}
protected abstract void apply(Type pluginType, IConfiguredInstance instance);
}
+For more information, see:
+ +So let me say upfront that I don't like this approach, but other folks have asked for this ability +over the years. Say that you have some legacy code where many concrete classes have a constructor argument +called "connectionString" that needs to be the connection string to the application database like these classes:
+
public class DatabaseUser
{
public string ConnectionString { get; set; }
public DatabaseUser(string connectionString)
{
ConnectionString = connectionString;
}
}
public class ConnectedThing
{
public string ConnectionString { get; set; }
public ConnectedThing(string connectionString)
{
ConnectionString = connectionString;
}
}
+Instead +of explicitly configuring every single concrete class in StructureMap with that inline constructor argument, +we can make a policy to do that in one place:
+
public class ConnectionStringPolicy : ConfiguredInstancePolicy
{
protected override void apply(Type pluginType, IConfiguredInstance instance)
{
var parameter = instance.Constructor.GetParameters().FirstOrDefault(x => x.Name == "connectionString");
if (parameter != null)
{
var connectionString = findConnectionStringFromConfiguration();
instance.Dependencies.AddForConstructorParameter(parameter, connectionString);
}
}
// find the connection string from whatever configuration
// strategy your application uses
private string findConnectionStringFromConfiguration()
{
return "the connection string";
}
}
+Now, let's use that policy against the types that need "connectionString" and see what happens:
+
[Fact]
public void use_the_connection_string_policy()
{
var container = new Container(_ =>
{
_.Policies.Add<ConnectionStringPolicy>();
});
container.GetInstance<DatabaseUser>()
.ConnectionString.ShouldBe("the connection string");
container.GetInstance<ConnectedThing>()
.ConnectionString.ShouldBe("the connection string");
}
+Years ago StructureMap was knocked by an "IoC expert" for not having this functionality. I said at the +time -- and still would -- that I would strongly recommend that you simply don't directly +open database connections in more than one or a very few spots in your code anyway. If I did +need to configure a database connection string in multiple concrete classes, I prefer strong typed configuration.
+From another common user request over the years, let's say that your application needs to connect to
+multiple databases, but your data access service in both cases is an interface called IDatabase
, and
+that's all the consumers of any database should ever need to know.
To make this concrete, let's say that our data access is all behind an interface and concrete class pair named
+Database/IDatabase
like so:
public interface IDatabase { }
public class Database : IDatabase
{
public string ConnectionString { get; set; }
public Database(string connectionString)
{
ConnectionString = connectionString;
}
public override string ToString()
{
return string.Format("ConnectionString: {0}", ConnectionString);
}
}
+For a registration policy, let's say that the parameter name of an IDatabase
dependency
+in a constructor function should match an identifier of one of the registered IDatabase
services.
+That policy would be:
public class InjectDatabaseByName : ConfiguredInstancePolicy
{
protected override void apply(Type pluginType, IConfiguredInstance instance)
{
instance.Constructor.GetParameters()
.Where(x => x.ParameterType == typeof(IDatabase))
.Each(param =>
{
// Using ReferencedInstance here tells StructureMap
// to "use the IDatabase by this name"
var db = new ReferencedInstance(param.Name);
instance.Dependencies.AddForConstructorParameter(param, db);
});
}
}
+And because I'm generally pretty boring about picking test data names, let's say that two of +our databases are named "red" and "green" with this container registration below:
+
var container = new Container(_ =>
{
_.For<IDatabase>().Add<Database>().Named("red")
.Ctor<string>("connectionString").Is("*red*");
_.For<IDatabase>().Add<Database>().Named("green")
.Ctor<string>("connectionString").Is("*green*");
_.Policies.Add<InjectDatabaseByName>();
});
+For more context, the classes that use IDatabase
would need to have constructor functions like
+these below:
public class BigService
{
public BigService(IDatabase green)
{
DB = green;
}
public IDatabase DB { get; set; }
}
public class ImportantService
{
public ImportantService(IDatabase red)
{
DB = red;
}
public IDatabase DB { get; set; }
}
public class DoubleDatabaseUser
{
public DoubleDatabaseUser(IDatabase red, IDatabase green)
{
Red = red;
Green = green;
}
// Watch out for potential conflicts between setters
// and ctor params. The easiest thing is to just make
// setters private
public IDatabase Green { get; private set; }
public IDatabase Red { get; private set; }
}
+Finally, we can exercise our new policy and see it in action:
+
// ImportantService should get the "red" database
container.GetInstance<ImportantService>()
.DB.As<Database>().ConnectionString.ShouldBe("*red*");
// BigService should get the "green" database
container.GetInstance<BigService>()
.DB.As<Database>().ConnectionString.ShouldBe("*green*");
// DoubleDatabaseUser gets both
var user = container.GetInstance<DoubleDatabaseUser>();
user.Green.As<Database>().ConnectionString.ShouldBe("*green*");
user.Red.As<Database>().ConnectionString.ShouldBe("*red*");
+How I prefer to do this - my strong preference would be to use separate interfaces for the different +databases even if that type is just an empty type marker that implements the same base. +I feel like using separate interfaces makes the code easier to trace and understand than trying +to make StructureMap vary dependencies based on naming conventions or what namespace a concrete type +happens to be in. At least now though, you have the choice of my way or using policies based on +naming conventions.
+Unlike the top two examples, this is taken from a strategy that I used in FubuMVC
+for its service registration. In that case, we wanted any concrete type whose name ended with
+"Cache" to be a singleton in the container registration. With the new IInstancePolicy
feature in StructureMap 4,
+we could create a new policy class like so:
public class CacheIsSingleton : IInstancePolicy
{
public void Apply(Type pluginType, Instance instance)
{
if (instance.ReturnedType.Name.EndsWith("Cache"))
{
instance.SetLifecycleTo<SingletonLifecycle>();
}
}
}
+
+Now, let's say that we have an interface named `IWidgets` and a single implementation called `WidgetCache` that
+should track our widgets in the application. Using our new policy, we should see `WidgetCache` being
+made a singleton:
+
+
[Fact]
public void set_cache_to_singleton()
{
var container = new Container(_ =>
{
_.Policies.Add<CacheIsSingleton>();
_.For<IWidgets>().Use<WidgetCache>();
});
// The policy is applied *only* at the time
// that StructureMap creates a "build plan"
container.GetInstance<IWidgets>()
.ShouldBeTheSameAs(container.GetInstance<IWidgets>());
// Now that the policy has executed, we
// can verify that WidgetCache is a SingletonThing
container.Model.For<IWidgets>().Default
.Lifecycle.ShouldBeOfType<SingletonLifecycle>();
}
+
+ Creating Registry
classes is the recommended way of using the Registry DSL.
The Registry DSL is mostly a fluent interface with some nested closure -usage. The intent of the Registry DSL is to make the configuration process as -error free as possible by using "compiler safe" expressions and defensive -programming to point out missing data.
-On all but the smallest systems, the main unit of configuration will probably be
-the Registry
class. Typically, you would subclass the Registry
class, then
-use the Fluent Interface methods exposed by the Registry class to create Container
-configuration. Here's a sample Registry
class below used to configure an
-instance of an IWidget
interface:
- public class PurpleRegistry : Registry
- {
- public PurpleRegistry()
- {
- For<IWidget>().Use<AWidget>();
- }
- }
-
-
-The next question is "how does my new Registry
class get used?"
When you set up a Container
or ObjectFactory
, you need to simply direct the
-Container
to use the configuration in that Registry
class:
- [Test]
- public void include_a_registry()
- {
- var registry = new Registry();
- registry.IncludeRegistry<YellowBlueRegistry>();
- registry.IncludeRegistry<RedGreenRegistry>();
- registry.IncludeRegistry<PurpleRegistry>();
- // build a container
- var container = new Container(registry);
- // verify the default implementation and total registered implementations
- container.GetInstance<IWidget>().ShouldBeOfType<AWidget>();
- container.GetAllInstances<IWidget>().Count().ShouldBe(5);
- }
-
-
-When you have multiple implementations of an interface, it can often be useful to -name instances. To retrieve a specific implementation:
-
- [Test]
- public void SimpleCaseWithNamedInstance()
- {
- container = new Container(x => { x.For<IWidget>().Add<AWidget>().Named("MyInstance"); });
- // retrieve an instance by name
- var widget = (AWidget) container.GetInstance<IWidget>("MyInstance");
- widget.ShouldNotBeNull();
- }
-
-
-You can also register named instances with the following shorthand:
-
- [Test]
- public void A_concrete_type_is_available_by_name_when_it_is_added_by_the_shorthand_mechanism()
- {
- IContainer container = new Container(r => r.For<IAddTypes>().AddInstances(x =>
- {
- x.Type<RedAddTypes>().Named("Red");
- x.Type<GreenAddTypes>().Named("Green");
- x.Type<BlueAddTypes>().Named("Blue");
- x.Type<PurpleAddTypes>();
- }));
- // retrieve the instances by name
- container.GetInstance<IAddTypes>("Red").IsType<RedAddTypes>();
- container.GetInstance<IAddTypes>("Green").IsType<GreenAddTypes>();
- container.GetInstance<IAddTypes>("Blue").IsType<BlueAddTypes>();
- }
-
-
-
-
- Creating Registry
classes is the recommended way of using the Registry DSL.
The Registry DSL is mostly a fluent interface with some nested closure +usage. The intent of the Registry DSL is to make the configuration process as +error free as possible by using "compiler safe" expressions and defensive +programming to point out missing data.
+On all but the smallest systems, the main unit of configuration will probably be
+the Registry
class. Typically, you would subclass the Registry
class, then
+use the fluent interface methods exposed by the Registry class to create Container
+configuration. Here's a sample Registry
class below used to configure an
+instance of an IWidget
interface:
public class PurpleRegistry : Registry
{
public PurpleRegistry()
{
For<IWidget>().Use<AWidget>();
}
}
+The next question is "how does my new Registry
class get used?"
When you set up a Container
, you need to simply direct the
+Container
to use the configuration in that Registry
class:
[Fact]
public void include_a_registry()
{
var registry = new Registry();
registry.IncludeRegistry<YellowBlueRegistry>();
registry.IncludeRegistry<RedGreenRegistry>();
registry.IncludeRegistry<PurpleRegistry>();
// build a container
var container = new Container(registry);
// verify the default implementation and total registered implementations
container.GetInstance<IWidget>().ShouldBeOfType<AWidget>();
container.GetAllInstances<IWidget>().Count().ShouldBe(5);
}
+Registrations in the Registry DSL can be done with either Add()
or Use()
methods, but they have
+a different semantic meaning to StructureMap. Add()
means add another Instance to this plugin type
+while Use()
means this one is the default.
One of the things that is different about StructureMap is that if it has multiple registrations of any
+given plugin type, one of these registrations has to be explicitly marked as the default usage for that plugin type
+or StructureMap will blow up in the call to Container.GetInstance()
. Other IoC tools will magically use
+the first registration or the last registration (and some even allow you to configure that behavior). We chose to
+make that determination be explicit.
As of StructureMap 3.0, the WhatDoIHave() output is part of any exception thrown by StructureMap when +it cannot determine a default registration for a requested type if there is more than one registration for that +type.
+If there are multiple calls to Use()
for the same plugin type, the last one wins. For more control over this behavior in
+modularity scenarios, see Fallback Services and Replace or Clear Out Previous Registrations.
To register the default Instance
of a type, the syntax is one of the Registry.For().Use()
overloads shown below:
public class SettingDefaults : Registry
{
public SettingDefaults()
{
// If you know the plugin type and its a closed type
// you can use this syntax
For<IWidget>().Use<DefaultWidget>();
// By Lambda
For<IWidget>().Use(() => new DefaultWidget());
// Pre-existing object
For<IWidget>().Use(new AWidget());
// This is rare now, but still valid
For<IWidget>().Add<AWidget>().Named("A");
For<IWidget>().Add<BWidget>().Named("B");
For<IWidget>().Use("A"); // makes AWidget the default
// Also rare, but you can supply an Instance object
// yourself for special needs
For<IWidget>().UseInstance(new MySpecialInstance());
// If you're registering an open generic type
// or you just have Type objects, use this syntax
For(typeof (IService<>)).Use(typeof (Service<>));
// This is occasionally useful for generic types
For(typeof (IService<>)).Use(new MySpecialInstance());
}
}
+To register additional Instances
for a plugin type, use one of the overloads of For().Add()
:
public class AdditionalRegistrations : Registry
{
public AdditionalRegistrations()
{
// If you know the plugin type and its a closed type
// you can use this syntax
For<IWidget>().Add<DefaultWidget>();
// By Lambda
For<IWidget>().Add(() => new DefaultWidget());
// Pre-existing object
For<IWidget>().Add(new AWidget());
// Also rare, but you can supply an Instance object
// yourself for special needs
For<IWidget>().AddInstance(new MySpecialInstance());
// If you're registering an open generic type
// or you just have Type objects, use this syntax
For(typeof(IService<>)).Add(typeof(Service<>));
// This is occasionally useful for generic types
For(typeof(IService<>)).Add(new MySpecialInstance());
}
}
+If you need to add several Instances
to a single plugin type, the AddInstances()
syntax
+shown below may be quicker and easier to use:
// registry is a StructureMap Registry object
registry.For<IService>().AddInstances(x =>
{
// Equivalent to For<IService>().Add<ColorService>().....
x.Type<ColorService>().Named("Red").Ctor<string>("color").Is("Red");
// Equivalent to For<IService>().Add(new ColorService("Yellow"))......
x.Object(new ColorService("Yellow")).Named("Yellow");
// Equivalent to For<IService>().Use(() => new ColorService("Purple"))....
x.ConstructedBy(() => new ColorService("Purple")).Named("Purple");
x.Type<ColorService>().Named("Decorated").Ctor<string>("color").Is("Orange");
});
+When you have multiple implementations of an interface, it can often be useful to +name instances. To retrieve a specific implementation:
+
[Fact]
public void SimpleCaseWithNamedInstance()
{
container = new Container(x => { x.For<IWidget>().Add<AWidget>().Named("MyInstance"); });
// retrieve an instance by name
var widget = (AWidget)container.GetInstance<IWidget>("MyInstance");
widget.ShouldNotBeNull();
}
+You can also register named instances with the following shorthand:
+
[Fact]
public void A_concrete_type_is_available_by_name_when_it_is_added_by_the_shorthand_mechanism()
{
IContainer container = new Container(r => r.For<IAddTypes>().AddInstances(x =>
{
x.Type<RedAddTypes>().Named("Red");
x.Type<GreenAddTypes>().Named("Green");
x.Type<BlueAddTypes>().Named("Blue");
x.Type<PurpleAddTypes>();
}));
// retrieve the instances by name
container.GetInstance<IAddTypes>("Red").IsType<RedAddTypes>();
container.GetInstance<IAddTypes>("Green").IsType<GreenAddTypes>();
container.GetInstance<IAddTypes>("Blue").IsType<BlueAddTypes>();
}
+
+ TODO(Write some content!)
- - -Integrating StructureMap into Common .Net Frameworks
-StructureMap is attempting to follow a strict SemVer versioning policy.
-Click on any release version to see the list of closed GitHub issues related to any of the 3.1 releases.
-IContext
Click on any release version to see the list of closed GitHub issues related to a bugfix release.
- -The exception messages provide contextual information about what StructureMap was trying to do when things went wrong.
-The nested container implementation is vastly improved, much faster (100X in my testing against a big application), and doesn’t have the massive singleton behavior bug from 2.6.*.
-All old [Obsolete]
2.5 registration syntax has been removed, and there’s been a major effort to enforce consistency throughout the registration API’s.
The original StructureMap.dll has been broken up into a couple pieces. The main assembly will be targeting PCL compliance thanks to the diligent efforts of Frank Quednau, and that means that Xml configuration and anything to do with ASP.Net has been devolved into separate assemblies and eventually into different Nuget packages. This means that StructureMap will theoretically support WP8 and other versions of .Net for the very first time. God help me.
-The strong naming has been removed. My thought is to distribute separate Nuget packages with unsigned versions for sane folks and signed versions for enterprise-y folks.
-Lifecycle (scope) can be set individually on each Instance (stupid limitation left over from the very early days) -Constructor selection can be specified per Instance.
-Improved diagnostics, both at runtime and for the container configuration.
-Improved runtime performance, especially for deep object graphs with inline dependencies (i.e.,
The interception model has been completely redesigned.
-The ancient attribute model for StructureMap configuration has been mostly removed.
-The “Profile” model has been much improved.
-The Xml configuration has been heavily streamlined.
-Internally, the old PipelineGraph
, InstanceFactory
, ProfileManager
architecture is all gone. The new PipelineGraph
implementations just wrap one or more PluginGraph
objects, so there’s vastly less data structure shuffling gone on internally.
Related links:
-StructureMap is attempting to follow a strict SemVer versioning policy.
+See the closed GitHub issues for +a complete list of changes.
+IContainer.With()
usages4.1 was mostly a bugfix release, but also included some new public API calls for type scanning discovery from *.exe files. +See the closed GitHub issues for details.
+4.0.1 was strictly a bug fix release.
+4.0 is a medium sized release that largely builds on the existing 3.0 architecture with significant improvements to conventional +registration via type scanning and several performance improvements as well as some bug fixes.
+The highlights:
+Registry.Scan()
) was completely rebuilt to make the model easier to extend and to
+optimize application bootstrapping in systems that heavily rely on StructureMap type scanning. See Auto-Registration and Conventions for more information.ObjectFactory
facade over the application Container
altogether.Registry.For<T>().ClearAll()
and Registry.For(Type).ClearAll()
methods for removing all previous registrations for a type. See
+Replace or Clear Out Previous Registrations for more information.See also the complete list of changes and issues for StructureMap 4.0.
+Click on any release version to see the list of closed GitHub issues related to any of the 3.1 releases.
+IContext
Click on any release version to see the list of closed GitHub issues related to a bugfix release.
+ +The exception messages provide contextual information about what StructureMap was trying to do when things went wrong.
+The nested container implementation is vastly improved, much faster (100X in my testing against a big application), and doesn’t have the massive singleton behavior bug from 2.6.*.
+All old [Obsolete]
2.5 registration syntax has been removed, and there’s been a major effort to enforce consistency throughout the registration API’s.
The original StructureMap.dll has been broken up into a couple pieces. The main assembly will be targeting PCL compliance thanks to the diligent efforts of Frank Quednau, and that means that Xml configuration and anything to do with ASP.Net has been devolved into separate assemblies and eventually into different Nuget packages. This means that StructureMap will theoretically support WP8 and other versions of .Net for the very first time. God help me.
+The strong naming has been removed. My thought is to distribute separate Nuget packages with unsigned versions for sane folks and signed versions for enterprise-y folks.
+Lifecycle (scope) can be set individually on each Instance (stupid limitation left over from the very early days) +Constructor selection can be specified per Instance.
+Improved diagnostics, both at runtime and for the container configuration.
+Improved runtime performance, especially for deep object graphs with inline dependencies (i.e.,
The interception model has been completely redesigned.
+The ancient attribute model for StructureMap configuration has been mostly removed.
+The “Profile” model has been much improved.
+The Xml configuration has been heavily streamlined.
+Internally, the old PipelineGraph
, InstanceFactory
, ProfileManager
architecture is all gone. The new PipelineGraph
implementations just wrap one or more PluginGraph
objects, so there’s vastly less data structure shuffling gone on internally.
Related links:
+Get all Services by Plugin Type
-You can also request a named configuration for a given PluginType by using the overloads of IContainer.GetInstance()
that take in a name like this:
- [Test]
- public void get_a_named_instance()
- {
- var container = new Container(x =>
- {
- x.For<IWidget>().Add<AWidget>().Named("A");
- x.For<IWidget>().Add<BWidget>().Named("B");
- x.For<IWidget>().Add<CWidget>().Named("C");
- });
-
- container.GetInstance<IWidget>("A").ShouldBeOfType<AWidget>();
- container.GetInstance<IWidget>("B").ShouldBeOfType<BWidget>();
- container.GetInstance<IWidget>("C").ShouldBeOfType<CWidget>();
-
- // or
-
- container.GetInstance(typeof (IWidget), "A").ShouldBeOfType<AWidget>();
- container.GetInstance(typeof (IWidget), "B").ShouldBeOfType<BWidget>();
- container.GetInstance(typeof (IWidget), "C").ShouldBeOfType<CWidget>();
- }
-
-
-
-
- You can also request a named configuration for a given PluginType by using the overloads of IContainer.GetInstance()
that take in a name like this:
[Fact]
public void get_a_named_instance()
{
var container = new Container(x =>
{
x.For<IWidget>().Add<AWidget>().Named("A");
x.For<IWidget>().Add<BWidget>().Named("B");
x.For<IWidget>().Add<CWidget>().Named("C");
});
container.GetInstance<IWidget>("A").ShouldBeOfType<AWidget>();
container.GetInstance<IWidget>("B").ShouldBeOfType<BWidget>();
container.GetInstance<IWidget>("C").ShouldBeOfType<CWidget>();
// or
container.GetInstance(typeof(IWidget), "A").ShouldBeOfType<AWidget>();
container.GetInstance(typeof(IWidget), "B").ShouldBeOfType<BWidget>();
container.GetInstance(typeof(IWidget), "C").ShouldBeOfType<CWidget>();
}
+
+ Get a Service by Plugin Type and Name
-Requesting the default configured object of a plugin type is done through the IContainer.GetInstance()
method shown below:
- [Test]
- public void get_the_default_instance()
- {
- var container = new Container(x => { x.For<IWidget>().Use<AWidget>(); });
-
- container.GetInstance<IWidget>()
- .ShouldBeOfType<AWidget>();
-
- // or
-
- container.GetInstance(typeof (IWidget))
- .ShouldBeOfType<AWidget>();
- }
-
-
-
-
- Requesting the default configured object of a plugin type is done through the IContainer.GetInstance()
method shown below:
[Fact]
public void get_the_default_instance()
{
var container = new Container(x => { x.For<IWidget>().Use<AWidget>(); });
container.GetInstance<IWidget>()
.ShouldBeOfType<AWidget>();
// or
container.GetInstance(typeof(IWidget))
.ShouldBeOfType<AWidget>();
}
+
+ Try Getting an Optional Service by Plugin Type
-Please see Working with Enumerable Types for a lot more information about what's going on behind the -scenes.
-Once in a while you might want to get an enumerable of all the configured objects for a PluginType. That's done with the GetAllInstances()
method shown below:
- [Test]
- public void get_all_instances()
- {
- var container = new Container(x =>
- {
- x.For<IWidget>().Add<AWidget>().Named("A");
- x.For<IWidget>().Add<BWidget>().Named("B");
- x.For<IWidget>().Add<CWidget>().Named("C");
- });
-
- container.GetAllInstances<IWidget>()
- .Select(x => x.GetType())
- .ShouldHaveTheSameElementsAs(typeof (AWidget), typeof (BWidget), typeof (CWidget));
-
- // or
-
- container.GetAllInstances(typeof (IWidget))
- .OfType<IWidget>() // returns an IEnumerable, so I'm casting here
- .Select(x => x.GetType())
- .ShouldHaveTheSameElementsAs(typeof (AWidget), typeof (BWidget), typeof (CWidget));
- }
-
-
-GetAllInstances()
respects the order in which the actual instances are configured in the Container. Be warned that some other IoC tools make different assuptions if you are coming from a different tool.Please see Working with Enumerable Types for a lot more information about what's going on behind the +scenes.
+Once in a while you might want to get an enumerable of all the configured objects for a PluginType. That's done with the GetAllInstances()
method shown below:
[Fact]
public void get_all_instances()
{
var container = new Container(x =>
{
x.For<IWidget>().Add<AWidget>().Named("A");
x.For<IWidget>().Add<BWidget>().Named("B");
x.For<IWidget>().Add<CWidget>().Named("C");
});
container.GetAllInstances<IWidget>()
.Select(x => x.GetType())
.ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));
// or
container.GetAllInstances(typeof(IWidget))
.OfType<IWidget>() // returns an IEnumerable, so I'm casting here
.Select(x => x.GetType())
.ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));
}
+GetAllInstances()
respects the order in which the actual instances are configured in the Container. Be warned that some other IoC tools make different assumptions if you are coming from a different tool.Most of the time you will be using StructureMap to build objects based on pre-canned configuration established upfront, but StructureMap
-also has the capability to supply dependencies by type or named parameters (if you know the name of constructor arguments or setter property names) to the Container at runtime using the IContainer.With()
methods.
Why would you use this? Here are a few examples from my own usage over the years:
-connectionString
constructor argument to connect to a different databaseNow, for some samples. Let's say that we have some classes like so:
-
- public class ColorWidget : IWidget
- {
- public string Color { get; set; }
-
- public ColorWidget(string color)
- {
- Color = color;
- }
- }
-
- public class GuyWithWidgetAndService
- {
- public IWidget Widget { get; set; }
- public IService Service { get; set; }
-
- public GuyWithWidgetAndService(IWidget widget, IService service)
- {
- Widget = widget;
- Service = service;
- }
- }
-
-
-and unless stated otherwise in a sample, a Container
configured like so:
- var container = new Container(x =>
- {
- x.For<IWidget>().Use<BWidget>();
- x.For<IService>().Use<AService>();
- });
-
-The original usage of explicit arguments was to replace primitive arguments to constructor functions like this sample:
-
- [Test]
- public void supply_named_arguments()
- {
- var container = new Container(x => { x.For<IWidget>().Use<ColorWidget>().Ctor<string>().Is("Red"); });
-
- container.GetInstance<IWidget>()
- .ShouldBeOfType<ColorWidget>()
- .Color.ShouldBe("Red");
-
- container.With("color").EqualTo("Blue")
- .GetInstance<IWidget>()
- .ShouldBeOfType<ColorWidget>()
- .Color.ShouldBe("Blue");
- }
-
-
-The canonical usage is overriding file paths, database connection string, or urls.
-You can invoke the explicit argument passing as a fluent interface starting with
-IContainer.With()
like the following sample:
- var widget = new BWidget();
- var service = new BService();
-
- var guyWithWidgetAndService = container
- .With<IWidget>(widget)
- .With<IService>(service)
- .GetInstance<GuyWithWidgetAndService>();
-
- guyWithWidgetAndService
- .Widget.ShouldBeTheSameAs(widget);
-
- guyWithWidgetAndService
- .Service.ShouldBeTheSameAs(service);
-
-If you dislike fluent interfaces or want to pass in a lot of dependencies, -the nested closure syntax might be more usable:
-
- var widget = new BWidget();
- var service = new BService();
-
- var guyWithWidgetAndService = container
- .With(x =>
- {
- x.With<IWidget>(widget);
- x.With<IService>(service);
- })
- .GetInstance<GuyWithWidgetAndService>();
-
- guyWithWidgetAndService
- .Widget.ShouldBeTheSameAs(widget);
-
- guyWithWidgetAndService
- .Service.ShouldBeTheSameAs(service);
-
-Finally, you can also pass an object of type ExplicitArguments
directly to an overload
-of the IContainer.GetInstance()
method:
- var widget = new BWidget();
- var service = new BService();
-
- var args = new ExplicitArguments();
- args.Set<IWidget>(widget);
- args.Set<IService>(service);
-
- var guyWithWidgetAndService = container
- .GetInstance<GuyWithWidgetAndService>(args);
-
- guyWithWidgetAndService
- .Widget.ShouldBeTheSameAs(widget);
-
- guyWithWidgetAndService
- .Service.ShouldBeTheSameAs(service);
-
-
-
- Most of the time you will be using StructureMap to build objects based on pre-canned configuration established upfront, but StructureMap
+also has the capability to supply dependencies by type or named parameters (if you know the name of constructor arguments or setter property names) to the Container at runtime using the IContainer.With()
methods.
Why would you use this? Here are a few examples from my own usage over the years:
+connectionString
constructor argument to connect to a different databaseNow, for some samples. Let's say that we have some classes like so:
+
public class ColorWidget : IWidget
{
public string Color { get; set; }
public ColorWidget(string color)
{
Color = color;
}
}
public class GuyWithWidgetAndService
{
public IWidget Widget { get; set; }
public IService Service { get; set; }
public GuyWithWidgetAndService(IWidget widget, IService service)
{
Widget = widget;
Service = service;
}
}
+and unless stated otherwise in a sample, a Container
configured like so:
var container = new Container(x =>
{
x.For<IWidget>().Use<BWidget>();
x.For<IService>().Use<AService>();
});
+The original usage of explicit arguments was to replace primitive arguments to constructor functions like this sample:
+
[Fact]
public void supply_named_arguments()
{
var container = new Container(x => { x.For<IWidget>().Use<ColorWidget>().Ctor<string>().Is("Red"); });
container.GetInstance<IWidget>()
.ShouldBeOfType<ColorWidget>()
.Color.ShouldBe("Red");
container.With("color").EqualTo("Blue")
.GetInstance<IWidget>()
.ShouldBeOfType<ColorWidget>()
.Color.ShouldBe("Blue");
}
+The canonical usage is overriding file paths, database connection string, or urls.
+You can invoke the explicit argument passing as a fluent interface starting with
+IContainer.With()
like the following sample:
var widget = new BWidget();
var service = new BService();
var guyWithWidgetAndService = container
.With<IWidget>(widget)
.With<IService>(service)
.GetInstance<GuyWithWidgetAndService>();
guyWithWidgetAndService
.Widget.ShouldBeTheSameAs(widget);
guyWithWidgetAndService
.Service.ShouldBeTheSameAs(service);
+If you dislike fluent interfaces or want to pass in a lot of dependencies, +the nested closure syntax might be more usable:
+
var widget = new BWidget();
var service = new BService();
var guyWithWidgetAndService = container
.With(x =>
{
x.With<IWidget>(widget);
x.With<IService>(service);
})
.GetInstance<GuyWithWidgetAndService>();
guyWithWidgetAndService
.Widget.ShouldBeTheSameAs(widget);
guyWithWidgetAndService
.Service.ShouldBeTheSameAs(service);
+Finally, you can also pass an object of type ExplicitArguments
directly to an overload
+of the IContainer.GetInstance()
method:
var widget = new BWidget();
var service = new BService();
var args = new ExplicitArguments();
args.Set<IWidget>(widget);
args.Set<IService>(service);
var guyWithWidgetAndService = container
.GetInstance<GuyWithWidgetAndService>(args);
guyWithWidgetAndService
.Widget.ShouldBeTheSameAs(widget);
guyWithWidgetAndService
.Service.ShouldBeTheSameAs(service);
+
+ StructureMap allows you to resolve instances of concrete classes without configuring that concrete type with a few provisos:
-Let's say we have the following object model, which represents the weather condition for a certain location.
-
- public class Weather
- {
- public Location Location { get; set; }
- public Atmosphere Atmosphere { get; set; }
- public Wind Wind { get; set; }
- public Condition Condition { get; set; }
-
- public Weather(Location location, Atmosphere atmosphere, Wind wind, Condition condition)
- {
- Location = location;
- Atmosphere = atmosphere;
- Wind = wind;
- Condition = condition;
- }
- }
-
- public class Location
- {
- //some properties
- }
-
- public class Atmosphere
- {
- //some properties
- }
-
- public class Wind
- {
- //some properties
- }
-
- public class Condition
- {
- //some properties
- }
-
-
-Before we can resolve the concrete Weather
type, we need an instance of an Container
object or ObjectFactory
. As mentioned earlier, these objects defines a generic GetInstance
method which can build us an instance of the Weather
type.
You can create a container yourself or use the statically accessed container.
-
- var container = new Container();
- var weather1 = container.GetInstance<Weather>();
-
- var weather2 = container.GetInstance<Weather>();
- weather2 = container.GetInstance<Weather>(); //short version for above.
-
-The reason why we don't need to supply any configuration is because StructureMap supports a concept called Auto Wiring. It's basically a smart way of building instances of types by looking to the constructors of the requested and all the needed underlaying types. During this inspection StructureMap also uses any provided configuration to help building the requested service or dependency.
-In our example, where there isn't any configuration available, StructureMap looks at the constructor of the requested Weather
type. It sees that it depends on four concrete types which all have a default constructor. StructureMap is therefore able to create an instance for all of them and inject them into the Weather
constructor. After that the Weather
instance is returned to the caller.
Most of the time you will be mapping abstractions to concrete types, but as you have seen StructureMap supports other use cases as well.
- - -StructureMap allows you to resolve instances of concrete classes without configuring that concrete type with a few provisos:
+Let's say we have the following object model, which represents the weather condition for a certain location.
+
public class Weather
{
public Location Location { get; set; }
public Atmosphere Atmosphere { get; set; }
public Wind Wind { get; set; }
public Condition Condition { get; set; }
public Weather(Location location, Atmosphere atmosphere, Wind wind, Condition condition)
{
Location = location;
Atmosphere = atmosphere;
Wind = wind;
Condition = condition;
}
}
public class Location
{
//some properties
}
public class Atmosphere
{
//some properties
}
public class Wind
{
//some properties
}
public class Condition
{
//some properties
}
+Before we can resolve the concrete Weather
type, we need an instance of an Container
object. As mentioned earlier, these objects defines a generic GetInstance
method which can build us an instance of the Weather
type.
You can create a container yourself or use the statically accessed container.
+
var container = new Container();
var weather1 = container.GetInstance<Weather>();
var weather2 = container.GetInstance<Weather>();
weather2 = container.GetInstance<Weather>(); //short version for above.
+The reason why we don't need to supply any configuration is because StructureMap supports a concept called Auto Wiring. It's basically a smart way of building instances of types by looking to the constructors of the requested and all the needed underlaying types. During this inspection StructureMap also uses any provided configuration to help building the requested service or dependency.
+In our example, where there isn't any configuration available, StructureMap looks at the constructor of the requested Weather
type. It sees that it depends on four concrete types which all have a default constructor. StructureMap is therefore able to create an instance for all of them and inject them into the Weather
constructor. After that the Weather
instance is returned to the caller.
Most of the time you will be mapping abstractions to concrete types, but as you have seen StructureMap supports other use cases as well.
+ +Try Geting an Optional Service by Plugin Type and Name
-In normal usage, if you ask StructureMap for a service and StructureMap doesn't recognize the requested type, the requested name, or know what the default should be for that type, StructureMap will fail fast by throwing an exception rather than returning a null. Sometimes though, you may want to
-retrieve an optional service from StructureMap that may or may not be registered in the Container. If that particular registration doesn't exist, you
-just want a null value. StructureMap provides first class support for optional dependencies through the usage of the IContainer.TryGetInstance()
methods.
Say you have a simple interface IFoo
that may or may not be registered in the Container:
- public interface IFoo
- {
- }
-
- public class Foo : IFoo
- {
- }
-
-
-In your own code you might request the IFoo
service like the code below, knowing that you'll
-take responsibility yourself for building the IFoo
service if StructureMap doesn't have a registration
-for IFoo
:
- public class MyFoo : IFoo
- {
- }
-
- [Test]
- public void real_usage()
- {
- var container = new Container();
-
- // if the container doesn't know about it,
- // I'll build it myself
- var foo = container.TryGetInstance<IFoo>()
- ?? new MyFoo();
- }
-
-
-Just to make this perfectly clear, if StructureMap has a default registration for IFoo
, you get this behavior:
- [Test]
- public void i_have_got_that()
- {
- var container = new Container(_ => _.For<IFoo>().Use<Foo>());
-
- container.TryGetInstance<IFoo>()
- .ShouldNotBeNull();
-
- // -- or --
-
- container.TryGetInstance(typeof (IFoo))
- .ShouldNotBeNull();
- }
-
-
-If StructureMap knows nothing about IFoo
, you get a null:
- [Test]
- public void i_do_not_have_that()
- {
- var container = new Container();
-
- container.TryGetInstance<IFoo>()
- .ShouldBeNull();
-
- // -- or --
-
- container.TryGetInstance(typeof (IFoo))
- .ShouldBeNull();
- }
-
-
-Since it's not a perfect world, there are some gotchas you need to be aware of.
-While StructureMap will happily auto-resolve concrete types that aren't registered,
-that does not apply to the TryGetInstance
mechanism:
- public class ConcreteThing
- {
- }
-
- [Test]
- public void no_auto_resolution_of_concrete_types()
- {
- var container = new Container();
-
- container.TryGetInstance<ConcreteThing>()
- .ShouldBeNull();
-
- // now register ConcreteThing and do it again
- container.Configure(_ => { _.For<ConcreteThing>().Use<ConcreteThing>(); });
-
- container.TryGetInstance<ConcreteThing>()
- .ShouldNotBeNull();
- }
-
-
-If you are using open generic types, the TryGetInstance()
mechanism can close the open generic registration
-to satisfy the optional dependency like this sample:
- public interface IThing<T>
- {
- }
-
- public class Thing<T> : IThing<T>
- {
- }
-
- [Test]
- public void can_try_get_open_type_resolution()
- {
- var container = new Container(_ => { _.For(typeof (IThing<>)).Use(typeof (Thing<>)); });
-
- container.TryGetInstance<IThing<string>>()
- .ShouldBeOfType<Thing<string>>();
- }
-
-
-
-
- In normal usage, if you ask StructureMap for a service and StructureMap doesn't recognize the requested type, the requested name, or know what the default should be for that type, StructureMap will fail fast by throwing an exception rather than returning a null. Sometimes though, you may want to
+retrieve an optional service from StructureMap that may or may not be registered in the Container. If that particular registration doesn't exist, you
+just want a null value. StructureMap provides first class support for optional dependencies through the usage of the IContainer.TryGetInstance()
methods.
Say you have a simple interface IFoo
that may or may not be registered in the Container:
public interface IFoo
{
}
public class Foo : IFoo
{
}
+In your own code you might request the IFoo
service like the code below, knowing that you'll
+take responsibility yourself for building the IFoo
service if StructureMap doesn't have a registration
+for IFoo
:
public class MyFoo : IFoo
{
}
[Fact]
public void real_usage()
{
var container = new Container();
// if the container doesn't know about it,
// I'll build it myself
var foo = container.TryGetInstance<IFoo>()
?? new MyFoo();
}
+Just to make this perfectly clear, if StructureMap has a default registration for IFoo
, you get this behavior:
[Fact]
public void i_have_got_that()
{
var container = new Container(_ => _.For<IFoo>().Use<Foo>());
container.TryGetInstance<IFoo>()
.ShouldNotBeNull();
// -- or --
container.TryGetInstance(typeof(IFoo))
.ShouldNotBeNull();
}
+If StructureMap knows nothing about IFoo
, you get a null:
[Fact]
public void i_do_not_have_that()
{
var container = new Container();
container.TryGetInstance<IFoo>()
.ShouldBeNull();
// -- or --
container.TryGetInstance(typeof(IFoo))
.ShouldBeNull();
}
+Since it's not a perfect world, there are some gotchas you need to be aware of.
+While StructureMap will happily auto-resolve concrete types that aren't registered,
+that does not apply to the TryGetInstance
mechanism:
public class ConcreteThing
{
}
[Fact]
public void no_auto_resolution_of_concrete_types()
{
var container = new Container();
container.TryGetInstance<ConcreteThing>()
.ShouldBeNull();
// now register ConcreteThing and do it again
container.Configure(_ => { _.For<ConcreteThing>().Use<ConcreteThing>(); });
container.TryGetInstance<ConcreteThing>()
.ShouldNotBeNull();
}
+If you are using open generic types, the TryGetInstance()
mechanism can close the open generic registration
+to satisfy the optional dependency like this sample:
public interface IThing<T>
{
}
public class Thing<T> : IThing<T>
{
}
[Fact]
public void can_try_get_open_type_resolution()
{
var container = new Container(_ => { _.For(typeof(IThing<>)).Use(typeof(Thing<>)); });
container.TryGetInstance<IThing<string>>()
.ShouldBeOfType<Thing<string>>();
}
+
+ StructureMap 3.0 marked a huge change in the StructureMap internals and public API's. -At this point, the StructureMap team is only focusing on bug fixes encountered by users and incremental features requested -on GitHub. Please log any suspected bugs or feature requests on StructureMap's GitHub page.
-Nothing definite has been planned at this point, but these are some of the things that the StructureMap team is considering for the future:
-StructureMap 3.0 released in early 2014 marked a huge change in the StructureMap internals and public API's. The 4.0 release was
+a much smaller release that primarily improved type scanning, diagnostics, and performance. The only breaking changes from 3 to 4 were in custom type scanning conventions, the removal of ObjectFactory
, and
+the elimination of some obscure configuration API's.
Please log any suspected bugs or feature requests on StructureMap's GitHub page.
+StructureMap can inject dependencies into public setter properties as part of its construction process using the Setter Injection form of Dependency Injection. The StructureMap team strongly recommends using constructor injection wherever possible instead of setter injection. That being said, +there are few cases where setter injection is probably easier (inheritance hierarchies), not to mention legacy or third party tools that +simply cannot support constructor injection cough ASP.Net cough.
+See this discussion from Martin Fowler on Constructor vs Setter Injection.
+If you are having any trouble with setter injection in your StructureMap usage, make sure you're familiar with using Build Plans +to help in troubleshooting
+The simplest conceptual way to force StructureMap into making public setters mandatory service dependencies by decorating setter properties with the [SetterProperty]
attribute like this example:
public class Repository
{
private IDataProvider _provider;
// Adding the SetterProperty to a setter directs
// StructureMap to use this property when
// constructing a Repository instance
[SetterProperty]
public IDataProvider Provider
{
set { _provider = value; }
}
[SetterProperty]
public bool ShouldCache { get; set; }
}
+Without the [SetterProperty]
attributes decorating the setters, StructureMap would ignore the Provider
and ShouldCache
properties when it builds up a Repository
object. With the attributes, StructureMap will try to build and attach values for the two properties as part of object construction.
If you were to look at StructureMap's "build plan" for the Repository
class, you would see something like this:
+PluginType: StructureMap.Testing.DocumentationExamples.Repository +Lifecycle: Transient +new Repository() + Set IDataProvider Provider = **Default** + Set Boolean ShouldCache = Value: False ++
If you intensely dislike runaway attribute usage, that's okay because there are other ways to enable setter injection in StructureMap.
+Any setter property not configured with [SetterProperty]
or the setter policies in the next section can still be filled by StructureMap if an inline dependency is configured matching that setter property as shown in the example below:
public class RuleWithSetters : IEventRule
{
public ICondition Condition { get; set; }
public IAction Action { get; set; }
public void ProcessEvent(SomeEvent @event)
{
if (Condition.Matches(@event))
{
Action.PerformWork(@event);
}
}
}
public class RuleWithSettersRegistry : Registry
{
public RuleWithSettersRegistry()
{
For<IEventRule>().Use<RuleWithSetters>()
.Setter<ICondition>().Is<Condition1>()
// or
.Setter(x => x.Action).Is(new Action1())
// or if you need to specify the name
.Setter<IAction>("Action").Is<Action2>()
// or you can configure values *after* the object
// is constructed with the SetProperty method
.SetProperty(x => x.Action = new Action2());
}
}
+See also:
+ +Lastly, you can give StructureMap some criteria for determining which setters should be mandatory dependencies with the Registry.Policies.SetAllProperties()
method during Container setup as shown in this example below:
public class ClassWithNamedProperties
{
public int Age { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public IGateway Gateway { get; set; }
public IService Service { get; set; }
}
[Fact]
public void specify_setter_policy_and_construct_an_object()
{
var theService = new ColorService("red");
var container = new Container(x =>
{
x.For<IService>().Use(theService);
x.For<IGateway>().Use<DefaultGateway>();
x.ForConcreteType<ClassWithNamedProperties>().Configure.Setter<int>().Is(5);
x.Policies.SetAllProperties(
policy => policy.WithAnyTypeFromNamespace("StructureMap.Testing.Widget3"));
});
var description = container.Model.For<ClassWithNamedProperties>().Default.DescribeBuildPlan();
Debug.WriteLine(description);
var target = container.GetInstance<ClassWithNamedProperties>();
target.Service.ShouldBeTheSameAs(theService);
target.Gateway.ShouldBeOfType<DefaultGateway>();
}
+All calls to Registry.Policies.SetAllProperties()
are additive, meaning you can use as many criteria as possible for setter injection.
You can run into situations where you'll want StructureMap to fill the setter dependencies of an object that is built outside of your own code and cannot be built by StructureMap itself. Action filter attributes from ASP.Net MVC are an obvious example.
+You're still in luck because StructureMap has the BuildUp(object)
method for just this scenario as shown in this example from the unit tests:
public class BuildUpTarget1
{
public IGateway Gateway { get; set; }
public IService Service { get; set; }
}
[Fact]
public void create_a_setter_rule_and_see_it_applied_in_BuildUp()
{
var theGateway = new DefaultGateway();
var container = new Container(x =>
{
x.For<IGateway>().Use(theGateway);
x.Policies.SetAllProperties(y => y.OfType<IGateway>());
});
var target = new BuildUpTarget1();
container.BuildUp(target);
target.Gateway.ShouldBeTheSameAs(theGateway);
target.Service.ShouldBeNull();
}
+The normal rules for what setters should be filled as described above apply to BuildUp()
.
Years ago I consulted for a company that had developed a successful software engine for pricing and analyzing potential energy trades. The next step for them was to adapt their pricing engine so that it could be embedded in other software packages or even a simple spreadsheet so that analysts could quickly try out "what if" scenarios before making any kind of deal. The immediate problem this firm had was that their pricing engine was architected such that the pricing engine business logic directly invoked their proprietary database schema and configuration files. The strategic pricing engine logic was effectively useless without all the rest of their system, so forget embedding the logic into spreadsheet logic.
+With the benefit of hindsight, if we were to build an energy trading pricing engine from scratch, we would probably opt to use the software design concept of Inversion of Control such that the actual pricing logic code would be handed all the pricing metadata it needed to perform its work instead of making the pricing logic reach out to get it. In its most general usage, Inversion of Control simply means that a component is given some sort of dependent data or service or configuration instead of that component having to "know" how to fetch or find that resource.
+An IoC container like StructureMap uses the Inversion of Control concept to simplify your internal services by freeing them from having to know how to find, build, or clean up their dependencies.
+Dependency Injection is nothing more than pushing dependencies of an object into constructor functions or setter properties instead of that object doing everything for itself. If you are strictly using Dependency Injection to fill the dependencies of your classes, your code should have no coupling to StructureMap itself.
+
public interface IDatabase { }
public class DatabaseUser
{
// Using Constructor Injection
public DatabaseUser(IDatabase database)
{
}
}
public class OtherDatabaseUser
{
// Setter Injection
public IDatabase Database { get; set; }
}
+StructureMap also fills the role of a service locator. In this usage, your code would directly access StructureMap's Container
class to build or resolve services upon demand like this sample:
public class ThirdDatabaseUser
{
private IDatabase _database;
public ThirdDatabaseUser(IContainer container)
{
// This is service location
_database = container.GetInstance<IDatabase>();
}
}
+Since IoC tools like StructureMap have come onto the software scene, many developers have very badly overused the service locator pattern and many other developers have become very vocal in their distaste for service location. The StructureMap team simply recommends that you favor Dependency Injection wherever possible, but that some service location in your system where you may need more advanced building options or lazy resolution of services is probably just fine.
+ +TODO(adapt old blog posts here)
-The best way to use an IoC container is to allow "Auto Wiring" to do most of the work for you. IoC Containers like StructureMap are an infrastructure concern, and as such, should be isolated from as much of your code as possible. Before examining Auto Wiring in depth, let's look at a common anti pattern of IoC usage:
+
// This is the wrong way to use an IoC container. Do NOT invoke the container from
// the constructor function. This tightly couples the ShippingScreenPresenter to
// the IoC container in a harmful way. This class cannot be used in either
// production or testing without a valid IoC configuration. Plus, you're writing more
// code
public ShippingScreenPresenter(IContainer container)
{
// It's even worse if you use a static facade to retrieve
// a service locator!
_service = container.GetInstance<IShippingService>();
_repository = container.GetInstance<IRepository>();
}
+Instead of binding ShippingScreenPresenter
so tightly to StructureMap and having to explicitly fetch its dependencies, let's switch
+it to using StructureMap a little more idiomatically and just exposing a constructor function with the necessary dependencies
+as arguments:
// This is the way to write a Constructor Function with an IoC tool
// Let the IoC container "inject" services from outside, and keep
// ShippingScreenPresenter ignorant of the IoC infrastructure
public ShippingScreenPresenter(IShippingService service, IRepository repository)
{
_service = service;
_repository = repository;
}
+As long as a StructureMap Container
knows how to resolve the IRepository
and
+IShippingService
interfaces, StructureMap can build ShippingScreenPresenter
by using "auto-wiring." All this means is that
+instead of forcing you to explicitly configure all the dependencies for ShippingScreenPresenter
, StructureMap can infer from
+the public constructor function and public property setters
+what dependencies ShippingScreenPresenter
needs and uses the defaults of both to build it out.
Looking at the build plan for ShippingScreenPresenter
:
public void ShowBuildPlan()
{
var container = new Container(_ =>
{
_.For<IShippingService>().Use<InternalShippingService>();
_.For<IRepository>().Use<SimpleRepository>();
});
// Just proving that we can build ShippingScreenPresenter;)
container.GetInstance<ShippingScreenPresenter>().ShouldNotBeNull();
var buildPlan = container.Model.For<ShippingScreenPresenter>().Default.DescribeBuildPlan(1);
Debug.WriteLine(buildPlan);
}
+give us:
++PluginType: StructureMap.Testing.DocumentationExamples.ShippingScreenPresenter +Lifecycle: Transient +new ShippingScreenPresenter(IShippingService, IRepository) + ┣ IShippingService = **Default** + ┃ | PluginType: StructureMap.Testing.DocumentationExamples.IShippingService + ┃ | Lifecycle: Transient + ┃ | new InternalShippingService() + ┃ + ┗ IRepository = **Default** + | PluginType: StructureMap.Testing.DocumentationExamples.IRepository + | Lifecycle: Transient + | new SimpleRepository() + ++
See Working with Primitive Types for more information on how StructureMap deals with primitive types like numbers, strings, enums, and dates in auto-wiring.
+ +Working with the IContext at Build Time
-TODO(Write some content!)
- + -This one is easy, any object marked as the Singleton lifecycle that implements IDisposable
is disposed when the root container is
+disposed:
[Fact]
public void singletons_are_disposed_when_the_container_is_disposed()
{
var container = new Container(_ =>
{
_.ForSingletonOf<DisposableSingleton>();
});
// As a singleton-scoped object, every request for DisposableSingleton
// will return the same object
var singleton = container.GetInstance<DisposableSingleton>();
singleton.ShouldBeSameAs(container.GetInstance<DisposableSingleton>());
singleton.ShouldBeSameAs(container.GetInstance<DisposableSingleton>());
singleton.ShouldBeSameAs(container.GetInstance<DisposableSingleton>());
singleton.ShouldBeSameAs(container.GetInstance<DisposableSingleton>());
singleton.WasDisposed.ShouldBeFalse();
// now, dispose the Container
container.Dispose();
// the SingletonThing scoped object should be disposed
singleton.WasDisposed.ShouldBeTrue();
}
+Ejecting a singleton-scoped object will also force it to be disposed. See Using the Container Model for more information on how to eject singletons
+from a running Container
.
As discussed in Nested Containers (Per Request/Transaction), any transient, AlwaysUnique (as of 4.0), or container-scoped object that implements IDisposable
and is created
+by a nested container will be disposed as the nested container is disposed:
[Fact]
public void nested_container_disposal()
{
var container = new Container(_ =>
{
// A SingletonThing scoped service
_.ForSingletonOf<IColorCache>().Use<ColorCache>();
// A transient scoped service
_.For<IColor>().Use<Green>();
// An AlwaysUnique scoped service
_.For<Purple>().AlwaysUnique();
});
ColorCache singleton = null;
Green nestedGreen = null;
Blue nestedBlue = null;
Purple nestedPurple = null;
using (var nested = container.GetNestedContainer())
{
// SingletonThing's are really built by the parent
singleton = nested.GetInstance<IColorCache>()
.ShouldBeOfType<ColorCache>();
nestedGreen = nested.GetInstance<IColor>()
.ShouldBeOfType<Green>();
nestedBlue = nested.GetInstance<Blue>();
nestedPurple = nested.GetInstance<Purple>();
}
// Transients created by the Nested Container
// are disposed
nestedGreen.WasDisposed.ShouldBeTrue();
nestedBlue.WasDisposed.ShouldBeTrue();
// Unique's created by the Nested Container
// are disposed
nestedPurple.WasDisposed.ShouldBeTrue();
// NOT disposed because it's owned by
// the parent container
singleton.WasDisposed.ShouldBeFalse();
}
+Regardless of the new tracking/release mode, the StructureMap team still strongly recommends using a nested container per HTTP request or service +bus message handling session or logical transaction to deal with disposing transient objects.
+By default, StructureMap will not hang on to any transient-scoped objects created by the root or child containers. Dealing with
+IDisposable
is completely up to the user in this case. The StructureMap team has long believed that trying to track transient disposables with
+an explicit Release(object)
mode as other IoC containers behave would do more harm than good (memory leaks from forgetting to call Release(), more work on the user).
That all being said, in order to comply with the new ASP.Net vNext compliance behavior, StructureMap 4.0 introduces a new opt-in transient tracking mode with the prerequisite Release(object)
method:
[Fact]
public void release_transient_created_by_root_container()
{
var container = new Container(_ => _.TransientTracking = TransientTracking.ExplicitReleaseMode);
container.TransientTracking.ShouldBeOfType<TrackingTransientCache>();
var transient1 = container.GetInstance<DisposableGuy>();
var transient2 = container.GetInstance<DisposableGuy>();
transient1.WasDisposed.ShouldBeFalse();
transient2.WasDisposed.ShouldBeFalse();
// release ONLY transient2
container.Release(transient2);
transient1.WasDisposed.ShouldBeFalse();
transient2.WasDisposed.ShouldBeTrue();
// transient2 should no longer be
// tracked by the container
container.TransientTracking.Tracked
.Single()
.ShouldBeTheSameAs(transient1);
}
[Fact]
public void disposing_the_container_disposes_tracked_transients()
{
var container = new Container(_ => _.TransientTracking = TransientTracking.ExplicitReleaseMode);
var transient1 = container.GetInstance<DisposableGuy>();
var transient2 = container.GetInstance<DisposableGuy>();
transient1.WasDisposed.ShouldBeFalse();
transient2.WasDisposed.ShouldBeFalse();
container.Dispose();
transient1.WasDisposed.ShouldBeTrue();
transient2.WasDisposed.ShouldBeTrue();
}
+As of right now, StructureMap will only track the top level object requested from a Container
and not all the other IDisposable
objects that may
+have been created as part of the main object graph.
It's not uncommon to want a single instance registration in StructureMap to be mapped to multiple +plugin type interfaces, especially if you have a class that implements multiple role interfaces +to support different consumers.
+As a simplified example, let's say that we have a class named StatefulCache
that will govern some kind
+of application wide state. Some consumers will only need to read or query data, so we'll create an IReader
+interface for that role. Other consumers will only make updates to the StatefulCache
, so we'll also have
+an IWriter
interface as shown below:
public interface IWriter { }
public interface IReader { }
public class StatefulCache : IReader, IWriter
{
}
+What we need from StructureMap is a way to make all requests to either IReader
and IWriter
+resolve to the same singleton object instance of StatefulCache
.
StructureMap provides the Forward<TFrom, TTo>()
mechanism for exactly this purpose:
[Fact]
public void stateful_cache_serves_multiple_interfaces()
{
var container = new Container(_ =>
{
// Let's make StatefulCache a SingletonThing in the container
_.ForConcreteType<StatefulCache>().Configure.Singleton();
_.Forward<StatefulCache, IReader>();
_.Forward<StatefulCache, IWriter>();
});
container.GetInstance<IReader>().ShouldBeOfType<StatefulCache>();
container.GetInstance<IWriter>().ShouldBeOfType<StatefulCache>();
}
+And because the syntax has consistently been confusing to users (including me even though I wrote it), +here's how to effect the same registration with lambda registrations:
+
[Fact]
public void equivalent()
{
var container = new Container(_ =>
{
// Let's make StatefulCache a SingletonThing in the container
_.ForConcreteType<StatefulCache>().Configure.Singleton();
_.For<IReader>().Use(c => c.GetInstance<StatefulCache>());
_.For<IWriter>().Use(c => c.GetInstance<StatefulCache>());
});
container.GetInstance<IReader>().ShouldBeOfType<StatefulCache>();
container.GetInstance<IWriter>().ShouldBeOfType<StatefulCache>();
}
+
+ TODO(Write some content!)
- + -Let's say that something asks StructureMap to resolve a named instance of a type that StructureMap does not know about. What if instead -of throwing the exception for an unknown named service, StructureMap could be taught to create a new registration for that type for the name -requested? That's the exact purpose of the Missing Named Instance feature in StructureMap.
-Using the contrived example from the StructureMap tests for this feature, let's say that you have a simple interface and object implementation like this:
-
- public interface Rule
- {
- }
-
- public class ColorRule : Rule
- {
- public string Color { get; set; }
-
- public ColorRule(string color)
- {
- Color = color;
- }
- }
-
-
-If a user asks the container for a named Rule
by a name and that rule doesn't exist, we'll just build
-a ColorRule
where the Color
property should be the name of the Instance requested. That registration
-and the usage is shown below:
- [Test]
- public void configure_and_use_missing_instance()
- {
- var container = new Container(x =>
- {
- x.For<Rule>().MissingNamedInstanceIs
- .ConstructedBy(context => new ColorRule(context.RequestedName));
- });
-
- container.GetInstance<Rule>("red")
- .ShouldBeOfType<ColorRule>().Color.ShouldBe("red");
-
- container.GetInstance<Rule>("green")
- .ShouldBeOfType<ColorRule>().Color.ShouldBe("green");
-
- container.GetInstance<Rule>("blue")
- .ShouldBeOfType<ColorRule>().Color.ShouldBe("blue");
- }
-
-
-The missing named instance rules are evaluated last, meaning that the container will still resolve -explicitly registered instances:
-
- [Test]
- public void does_not_override_explicit_registrations()
- {
- var container = new Container(x =>
- {
- x.For<Rule>().Add(new ColorRule("DarkRed")).Named("red");
-
- x.For<Rule>().MissingNamedInstanceIs
- .ConstructedBy(context => new ColorRule(context.RequestedName));
- });
-
- container.GetInstance<Rule>("red")
- .ShouldBeOfType<ColorRule>()
- .Color.ShouldBe("DarkRed");
- }
-
-
-You also have the ability to explicitly supply an Instance
to be evaluated in the missing named instance
-resolution:
- [Test]
- public void configure_and_use_missing_instance_by_generic_registration()
- {
- var instance = new LambdaInstance<ColorRule>(c => new ColorRule(c.RequestedName));
-
- var container = new Container(x =>
- {
- x.For(typeof (Rule))
- .MissingNamedInstanceIs(instance);
- });
-
- container.GetInstance<Rule>("red").ShouldBeOfType<ColorRule>().Color.ShouldBe("red");
- container.GetInstance<Rule>("green").ShouldBeOfType<ColorRule>().Color.ShouldBe("green");
- container.GetInstance<Rule>("blue").ShouldBeOfType<ColorRule>().Color.ShouldBe("blue");
- }
-
-
-To the best of my recollection, the feature described in this section was designed for a multi-tenancy situation where -we needed to allow the business rules to vary by client, but most clients would still be using the default rules. In our -implemenation, we would make a service location call to the container for the rules by the client id and use the -object returned to calculate the business rules (it was an invoice processing service).
-If our rules logic class structure looked like:
-
- public interface Rule
- {
- }
-
- public class DefaultRule : Rule
- {
- }
-
- public class Client1Rule : Rule
- {
- }
-
- public class Client2Rule : Rule
- {
- }
-
-
-then we could allow client specific rules while still allowing the container to fall through to the default rules -for clients that don't need customized rules:
-
- [Test]
- public void use_customer_overrides()
- {
- var container = new Container(_ =>
- {
- _.For<Rule>().MissingNamedInstanceIs.Type<DefaultRule>();
-
- _.For<Rule>().Add<Client1Rule>().Named("client1");
- _.For<Rule>().Add<Client2Rule>().Named("client2");
- });
-
- // Client1 & Client2 have explicit registrations
- container.GetInstance<Rule>("client1").ShouldBeOfType<Client1Rule>();
- container.GetInstance<Rule>("client2").ShouldBeOfType<Client2Rule>();
-
- // Client3 has no explicit registration, so falls through to
- // DefaultRule
- container.GetInstance<Rule>("client3").ShouldBeOfType<DefaultRule>();
- }
-
-
-In a more complex usage, maybe you need to pull client specific information from a database or configuration files -to construct the rules object. The code below is a partial sample of how you might use the missing named instance -feature to do data lookups inside of StructureMap:
-
- public interface IClientRulesRepsitory
- {
- ClientRulesData Find(string clientName);
- }
-
- public class ClientRulesData
- {
- }
-
- public class DataUsingRule : Rule
- {
- private readonly ClientRulesData _data;
-
- public DataUsingRule(ClientRulesData data)
- {
- _data = data;
- }
- }
-
- [Test]
- public void register_by_looking_up_data()
- {
- var container = new Container(_ =>
- {
- _.For<Rule>().MissingNamedInstanceIs.ConstructedBy(
- "Building client rules by looking up client data", c =>
- {
- var data = c.GetInstance<IClientRulesRepsitory>()
- .Find(c.RequestedName);
-
- return new DataUsingRule(data);
- });
- });
- }
-
-
-
-
- Let's say that something asks StructureMap to resolve a named instance of a type that StructureMap does not know about. What if instead +of throwing the exception for an unknown named service, StructureMap could be taught to create a new registration for that type for the name +requested? That's the exact purpose of the Missing Named Instance feature in StructureMap.
+Using the contrived example from the StructureMap tests for this feature, let's say that you have a simple interface and object implementation like this:
+
public interface Rule
{
}
public class ColorRule : Rule
{
public string Color { get; set; }
public ColorRule(string color)
{
Color = color;
}
}
+If a user asks the container for a named Rule
by a name and that rule doesn't exist, we'll just build
+a ColorRule
where the Color
property should be the name of the Instance requested. That registration
+and the usage is shown below:
[Fact]
public void configure_and_use_missing_instance()
{
var container = new Container(x =>
{
x.For<Rule>().MissingNamedInstanceIs
.ConstructedBy(context => new ColorRule(context.RequestedName));
});
container.GetInstance<Rule>("red")
.ShouldBeOfType<ColorRule>().Color.ShouldBe("red");
container.GetInstance<Rule>("green")
.ShouldBeOfType<ColorRule>().Color.ShouldBe("green");
container.GetInstance<Rule>("blue")
.ShouldBeOfType<ColorRule>().Color.ShouldBe("blue");
}
+The missing named instance rules are evaluated last, meaning that the container will still resolve +explicitly registered instances:
+
[Fact]
public void does_not_override_explicit_registrations()
{
var container = new Container(x =>
{
x.For<Rule>().Add(new ColorRule("DarkRed")).Named("red");
x.For<Rule>().MissingNamedInstanceIs
.ConstructedBy(context => new ColorRule(context.RequestedName));
});
container.GetInstance<Rule>("red")
.ShouldBeOfType<ColorRule>()
.Color.ShouldBe("DarkRed");
}
+You also have the ability to explicitly supply an Instance
to be evaluated in the missing named instance
+resolution:
[Fact]
public void configure_and_use_missing_instance_by_generic_registration()
{
var instance = new LambdaInstance<ColorRule>(c => new ColorRule(c.RequestedName));
var container = new Container(x =>
{
x.For(typeof(Rule))
.MissingNamedInstanceIs(instance);
});
container.GetInstance<Rule>("red").ShouldBeOfType<ColorRule>().Color.ShouldBe("red");
container.GetInstance<Rule>("green").ShouldBeOfType<ColorRule>().Color.ShouldBe("green");
container.GetInstance<Rule>("blue").ShouldBeOfType<ColorRule>().Color.ShouldBe("blue");
}
+To the best of my recollection, the feature described in this section was designed for a multi-tenancy situation where +we needed to allow the business rules to vary by client, but most clients would still be using the default rules. In our +implemenation, we would make a service location call to the container for the rules by the client id and use the +object returned to calculate the business rules (it was an invoice processing service).
+If our rules logic class structure looked like:
+
public interface Rule
{
}
public class DefaultRule : Rule
{
}
public class Client1Rule : Rule
{
}
public class Client2Rule : Rule
{
}
+then we could allow client specific rules while still allowing the container to fall through to the default rules +for clients that don't need customized rules:
+
[Fact]
public void use_customer_overrides()
{
var container = new Container(_ =>
{
_.For<Rule>().MissingNamedInstanceIs.Type<DefaultRule>();
_.For<Rule>().Add<Client1Rule>().Named("client1");
_.For<Rule>().Add<Client2Rule>().Named("client2");
});
// Client1 & Client2 have explicit registrations
container.GetInstance<Rule>("client1").ShouldBeOfType<Client1Rule>();
container.GetInstance<Rule>("client2").ShouldBeOfType<Client2Rule>();
// Client3 has no explicit registration, so falls through to
// DefaultRule
container.GetInstance<Rule>("client3").ShouldBeOfType<DefaultRule>();
}
+In a more complex usage, maybe you need to pull client specific information from a database or configuration files +to construct the rules object. The code below is a partial sample of how you might use the missing named instance +feature to do data lookups inside of StructureMap:
+
public interface IClientRulesRepsitory
{
ClientRulesData Find(string clientName);
}
public class ClientRulesData
{
}
public class DataUsingRule : Rule
{
private readonly ClientRulesData _data;
public DataUsingRule(ClientRulesData data)
{
_data = data;
}
}
[Fact]
public void register_by_looking_up_data()
{
var container = new Container(_ =>
{
_.For<Rule>().MissingNamedInstanceIs.ConstructedBy(
"Building client rules by looking up client data", c =>
{
var data = c.GetInstance<IClientRulesRepsitory>()
.Find(c.RequestedName);
return new DataUsingRule(data);
});
});
}
+
+ Instead of allowing StructureMap to build objects directly, you can give a StructureMap Container
a Lambda function that can be called to create an object at resolution time.
Using NHibernate's ISession
as an example
+of an object that typically has to be built by using an ISessionFactory
object:
public interface ISession { }
public interface ISessionFactory
{
ISession Build();
}
+If we want to allow StructureMap to control the ISession
lifecycle and creation, we have to register a Lambda function as the
+means of creating ISession
as shown in this example below:
public class SessionFactoryRegistry : Registry
{
// Let's not worry about how ISessionFactory is built
// in this example
public SessionFactoryRegistry(ISessionFactory factory)
{
For<ISessionFactory>().Use(factory);
// Build ISession with a lambda:
For<ISession>().Use("Build ISession from ISessionFactory", c =>
{
// To resolve ISession, I first pull out
// ISessionFactory from the IContext and use that
// to build a new ISession.
return c.GetInstance<ISessionFactory>().Build();
});
}
}
+Lambda registrations can be done with any of the following four signatures:
+(Expression<Func<IContext, T>> builder)
-- a simple, one line Lambda to build T
using IContext
(Expression<Func<T>> func)
-- a simple, one line Lambda to build T
(string description, Func<IContext, T> builder)
-- use IContext
in your builder Lambda with a user-supplied description for diagnostics(string description, Func<T> builder)
-- Supply a complex Func<T>
with a user-supplied description for diagnosticsBe very wary of the difference between legal Expression's
and more complicated Lambda's that will need to be Func's
. It likely doesn't matter to
+you the user, but it unfortunately does to StructureMap and .Net itself. If you need to use a more complex Func
, you will have
+to supply a diagnostic description.
See Working with the IContext at Build Time for more information.
+ +StructureMap has some built in functionality for "lazy" resolved dependencies, so that instead of your
+application service taking a direct dependency on IExpensiveToBuildService
that might not be necessary,
+you could instead have StructureMap fulfil a dependency on Lazy<IExpensiveToBuildService>
or Func<IExpensiveToBuildService>
+that could be used to retrieve that expensive service only when it is needed from whatever Container
originally created
+the parent object.
Do note that the Lazy<T>
and Func<T>
approaches respect the lifecycle of the underlying registration rather than
+automatically building a unique object instance.
Also note that Lazy<T>
or Func<T>
is your best (only) viable approach if you wish to have StructureMap inject bi-directional
+relationships.
Assuming that StructureMap either has an existing configuration for T
or can
+derive a way to build T
, you can just declare a dependency on Lazy<T>
like this sample:
public class WidgetLazyUser
{
private readonly Lazy<IWidget> _widget;
public WidgetLazyUser(Lazy<IWidget> widget)
{
_widget = widget;
}
public IWidget Widget
{
get { return _widget.Value; }
}
}
[Fact]
public void lazy_resolution_in_action()
{
var container = new Container(_ =>
{
_.For<IWidget>().Use<AWidget>();
});
container.GetInstance<WidgetLazyUser>()
.Widget.ShouldBeOfType<AWidget>();
}
+Likewise, you can also declare a dependency on Func<T>
with very similar mechanics:
[Fact]
public void build_a_func_that_returns_a_singleton()
{
var container = new Container(x =>
{
x.ForSingletonOf<IWidget>().Use<ColorWidget>().Ctor<string>("color").Is("green");
});
var func = container.GetInstance<Func<IWidget>>();
var w1 = func();
var w2 = func();
var w3 = func();
w1.ShouldBeOfType<ColorWidget>().Color.ShouldBe("green");
w1.ShouldBeTheSameAs(w2);
w1.ShouldBeTheSameAs(w3);
w2.ShouldBeTheSameAs(w3);
}
+This functionality predates the introduction of the Lazy type to .Net
+Finally, you can also declare a dependency on Func<string, T>
that will allow you to lazily
+resolve a dependency of T
by name:
[Fact]
public void build_a_func_by_string()
{
var container = new Container(x =>
{
x.For<IWidget>().Add<ColorWidget>().Ctor<string>("color").Is("green").Named("green");
x.For<IWidget>().Add<ColorWidget>().Ctor<string>("color").Is("blue").Named("blue");
x.For<IWidget>().Add<ColorWidget>().Ctor<string>("color").Is("red").Named("red");
});
var func = container.GetInstance<Func<string, IWidget>>();
func("green").ShouldBeOfType<ColorWidget>().Color.ShouldBe("green");
}
+StructureMap does not directly support bi-directional dependency relationships -- but will happily tell you in an exception when
+you accidentally manage to create one without cratering your AppDomain with a StackOverflowException
.
Either Func<T>
or Lazy<T>
can be used as a workaround for purposeful bi-directional dependencies between types. The
+following is an example of using this strategy:
[Singleton]
public class Thing1
{
private readonly Lazy<Thing2> _thing2;
public Thing1(Lazy<Thing2> thing2)
{
_thing2 = thing2;
}
public Thing2 Thing2
{
get { return _thing2.Value; }
}
}
[Singleton]
public class Thing2
{
public Thing1 Thing1 { get; set; }
public Thing2(Thing1 thing1)
{
Thing1 = thing1;
}
}
[Fact]
public void use_lazy_as_workaround_for_bi_directional_dependency()
{
var container = new Container();
var thing1 = container.GetInstance<Thing1>();
var thing2 = container.GetInstance<Thing2>();
thing1.Thing2.ShouldBeSameAs(thing2);
thing2.Thing1.ShouldBeSameAs(thing1);
}
+
+ Nested Container's are a powerful feature in StructureMap for service resolution and clean object disposal in the -context of short lived operations. Nested Container's were introduced in version 2.6, but greatly improved in both performance (100X reduction in the time to create a nested container in a large application) and ahem lifecycle -mechanics as a major goal of the 3.0 release.
-The original use case and impetus for building this feature was a simplistic message handling system that dequeued
-messages from a Sql Server table (please forget for a second the wisdom of using Sql Server as a queueing system), deserialized
-the contents into a .Net object, then created the proper handler object for that message type and executed that handler -- all within
-a single transaction. What we wanted at the time was a way to track and clean up all IDisposable
objects created during the lifespan of each
-transaction. We also wanted a new type of object lifecycle where objects like the NHibernate ISession would be shared by every object
-created during the lifetime of the nested container -- even if the ISession
was resolved lazily after the intial
-resolution of the message handler. The result was what is now the nested container feature
-of StructureMap.
Why not just use HttpContext
based lifecycles like we've always done in the past? Because HttpContext
is not supported by the any
-type of OWIN web host and will not be a part of ASP.Net vNext. Using a Nested Container per HTTP request is a better, lighterweight way
-to scope services to an HTTP request without coupling your code to what will soon be legacy ASP.Net runtime code.
At the time of this document, Nested Container's per HTTP request are supported by frameworks like FubuMVC, -ASP.Net MVC through the StructureMap.MVC5 nuget package, and Web API with the StructureMap.WebApi2 nuget. Several service bus frameworks also use a StructureMap nested container per message invocation including FubuTransportation, -MassTransit, and NServiceBus.
-Creating a nested container is as simple as calling the IContainer.GetNestedContainer()
method as shown below:
- public interface IWorker
- {
- void DoWork();
- }
-
- public class Worker : IWorker, IDisposable
- {
- public void DoWork()
- {
- // do stuff!
- }
-
- public void Dispose()
- {
- // clean up
- }
- }
-
- [Test]
- public void creating_a_nested_container()
- {
- // From an IContainer object
- var container = new Container(_ => { _.For<IWorker>().Use<Worker>(); });
-
- using (var nested = container.GetNestedContainer())
- {
- // This object is disposed when the nested container
- // is disposed
- var worker = nested.GetInstance<IWorker>();
- worker.DoWork();
- }
- }
-
-
-While StructureMap supports several object instance lifecycles out of the boxy, in idiomatic usage of StructureMap the only common lifecyles are:
-Transient
- The default lifecycle. A new object is created for a configured Instance on each request to the containerSingleton
- One instance is constructed and used over the entire Container lifetimeIn the context of a Nested Container however, the Transient
scoping now applies to the Nested Container itself:
- [Test]
- public void nested_container_behavior_of_transients()
- {
- // "Transient" is the default lifecycle
- // in StructureMap
- var container = new Container(_ => { _.For<IColor>().Use<Green>(); });
-
- // In a normal Container, a "transient" lifecycle
- // Instance will be built up once in every request
- // to the Container
- container.GetInstance<IColor>()
- .ShouldNotBeTheSameAs(container.GetInstance<IColor>());
-
- // From a nested container, the "transient" lifecycle
- // is tracked to the nested container
- using (var nested = container.GetNestedContainer())
- {
- nested.GetInstance<IColor>()
- .ShouldBeTheSameAs(nested.GetInstance<IColor>());
-
- // One more time
- nested.GetInstance<IColor>()
- .ShouldBeTheSameAs(nested.GetInstance<IColor>());
- }
- }
-
-
-Instance's
scoped to anything but Transient
are resolved as normal, but through the parent container:
- [Test]
- public void nested_container_usage_of_singletons()
- {
- var container = new Container(_ => { _.ForSingletonOf<IColorCache>().Use<ColorCache>(); });
-
- var singleton = container.GetInstance<IColorCache>();
-
- // Singleton's are resolved from the parent container
- using (var nested = container.GetNestedContainer())
- {
- nested.GetInstance<IColorCache>()
- .ShouldBeTheSameAs(singleton);
- }
- }
-
-
-See <linkto:object-lifecycle]> for more information on supported object lifecycles.
-A nested container is a new Container object that still retains access to the parent container that created it so that it can -efficiently share registrations, policies, and cached build plan's. You can, however, register register services into the nested container that override the parent container.
-The FubuMVC web framework uses a nested container per HTTP request. During an HTTP request, FubuMVC injects services -for the current HTTP request and response to a nested container before creating the actual services that will handle the request. The -FubuMVC mechanics are conceptually similar to this code sample:
-
- [Test]
- public void overriding_services_in_a_nested_container()
- {
- var container = new Container(_ =>
- {
- _.For<IHttpRequest>().Use<StandInHttpRequest>();
- _.For<IHttpResponse>().Use<StandInHttpResponse>();
- });
-
- var request = new HttpRequest();
- var response = new HttpResponse();
-
- using (var nested = container.GetNestedContainer())
- {
- // Override the HTTP request and response for this
- // nested container
- nested.Configure(_ =>
- {
- _.For<IHttpRequest>().Use(request);
- _.For<IHttpResponse>().Use(response);
- });
-
- var handler = nested.GetInstance<HttpRequestHandler>();
- handler.Request.ShouldBeTheSameAs(request);
- handler.Response.ShouldBeTheSameAs(response);
- }
-
- // Outside the nested container, we still have the original
- // registrations
- container.GetInstance<IHttpRequest>()
- .ShouldBeOfType<StandInHttpRequest>();
-
- container.GetInstance<IHttpResponse>()
- .ShouldBeOfType<StandInHttpResponse>();
- }
-
-
-When handling requests for new services, a nested container first checks its own configuration if it has its own explicit registration for the request. If the nested container does have an explicit registration, it uses that registration. Otherwise, a nested container will attempt to build -an object using the registered configuration of its parent container.
-Nested container object lifecycles equally apply to objects resolved lazily with
-either Lazy<T>
, Func<T>
, or Func<string, T>
as shown below:
- public class Foo
- {
- }
-
- public class FooHolder
- {
- public IContainer Container { get; set; }
- public Func<Foo> Func { get; set; }
- public Lazy<Foo> Lazy { get; set; }
-
- public FooHolder(IContainer container, Func<Foo> func, Lazy<Foo> lazy)
- {
- Container = container;
- Func = func;
- Lazy = lazy;
- }
- }
-
- [Test]
- public void service_location_and_container_resolution_inside_nested_containers()
- {
- var container = new Container();
-
- using (var nested = container.GetNestedContainer())
- {
- var holder = nested.GetInstance<FooHolder>();
-
- // The injected IContainer is the nested container
- holder.Container.ShouldBeTheSameAs(nested);
-
- // Func<T> and Lazy<T> values will be built by
- // the nested container w/ the nested container
- // scoping
- var nestedFoo = nested.GetInstance<Foo>();
-
- holder.Func().ShouldBeTheSameAs(nestedFoo);
- holder.Lazy.Value.ShouldBeTheSameAs(nestedFoo);
- }
- }
-
-
-IContainer
object injected above was the nested container that
-created the FooHandler
object. If you do want to use service location within an object, just take in
-IContainer
as a constructor dependency and you will always get the correctly scoped IContainer
.You can created nested containers from profile containers as shown in the sample below:
-<sample:nested-profiles]>
-See Profiles and Child Containers for more information about using profiles.
-As stated above, disposing a nested container will also dispose all objects created with the default Transient lifecycle by the
-nested container that implement the IDisposable
interface. That behavior is demonstrated
-below:
- [Test]
- public void nested_container_disposal()
- {
- var container = new Container(_ =>
- {
- // A singleton scoped service
- _.ForSingletonOf<IColorCache>().Use<ColorCache>();
-
- // A transient scoped service
- _.For<IColor>().Use<Green>();
- });
-
- ColorCache singleton = null;
- Green nestedGreen = null;
- Blue nestedBlue = null;
-
- using (var nested = container.GetNestedContainer())
- {
- // Singleton's are really built by the parent
- singleton = nested.GetInstance<IColorCache>()
- .ShouldBeOfType<ColorCache>();
-
- nestedGreen = nested.GetInstance<IColor>()
- .ShouldBeOfType<Green>();
-
-
- nestedBlue = nested.GetInstance<Blue>();
- }
-
- // Transients created by the Nested Container
- // are disposed, but no other lifecycle is
- // disposed
- nestedGreen.WasDisposed.ShouldBeTrue();
- nestedBlue.WasDisposed.ShouldBeTrue();
-
- // NOT disposed because it's owned by
- // the parent container
- singleton.WasDisposed.ShouldBeFalse();
- }
-
-
-For the sake of clarity, the classes used in the sample above are:
-
- public interface IColor
- {
- }
-
- public class Red : IColor
- {
- }
-
- public class Blue : IColor, IDisposable
- {
- public bool WasDisposed;
-
- public void Dispose()
- {
- WasDisposed = true;
- }
- }
-
- public class Green : IColor, IDisposable
- {
- public bool WasDisposed;
-
- public void Dispose()
- {
- WasDisposed = true;
- }
- }
-
- public interface IColorCache
- {
- }
-
- public class ColorCache : IColorCache, IDisposable
- {
- public bool WasDisposed;
-
- public void Dispose()
- {
- WasDisposed = true;
- }
- }
-
-
-
-
- Nested Container's are a powerful feature in StructureMap for service resolution and clean object disposal in the +context of short lived operations. Nested Container's were introduced in version 2.6, but greatly improved in both performance (100X reduction in the time to create a nested container in a large application) and ahem lifecycle +mechanics as a major goal of the 3.0 release.
+The original use case and impetus for building this feature was a simplistic message handling system that dequeued
+messages from a Sql Server table (please forget for a second the wisdom of using Sql Server as a queueing system), deserialized
+the contents into a .Net object, then created the proper handler object for that message type and executed that handler -- all within
+a single transaction. What we wanted at the time was a way to track and clean up all IDisposable
objects created during the lifespan of each
+transaction. We also wanted a new type of object lifecycle where objects like the NHibernate ISession would be shared by every object
+created during the lifetime of the nested container -- even if the ISession
was resolved lazily after the intial
+resolution of the message handler. The result was what is now the nested container feature
+of StructureMap.
Why not just use HttpContext
based lifecycles like we've always done in the past? Because HttpContext
is not supported by any
+type of OWIN web host and will not be a part of ASP.Net vNext. Using a Nested Container per HTTP request is a better, lighterweight way
+to scope services to an HTTP request without coupling your code to what will soon be legacy ASP.Net runtime code.
At the time of this document, Nested Container's per HTTP request are supported by frameworks like FubuMVC, +ASP.Net MVC through the StructureMap.MVC5 nuget package, and Web API with the StructureMap.WebApi2 nuget. Several service bus frameworks also use a StructureMap nested container per message invocation including FubuTransportation, +MassTransit, and NServiceBus.
+Creating a nested container is as simple as calling the IContainer.GetNestedContainer()
method as shown below:
public interface IWorker
{
void DoWork();
}
public class Worker : IWorker, IDisposable
{
public void DoWork()
{
// do stuff!
}
public void Dispose()
{
// clean up
}
}
[Fact]
public void creating_a_nested_container()
{
// From an IContainer object
var container = new Container(_ => { _.For<IWorker>().Use<Worker>(); });
using (var nested = container.GetNestedContainer())
{
// This object is disposed when the nested container
// is disposed
var worker = nested.GetInstance<IWorker>();
worker.DoWork();
}
}
+While StructureMap supports several object instance lifecycles out of the box, in idiomatic usage of StructureMap the only common lifecyles are:
+Transient
- The default lifecycle. A new object is created for a configured Instance on each request to the containerSingleton
- One instance is constructed and used over the entire Container lifetimeIn the context of a Nested Container however, the Transient
scoping now applies to the Nested Container itself:
[Fact]
public void nested_container_behavior_of_transients()
{
// "Transient" is the default lifecycle
// in StructureMap
var container = new Container(_ => { _.For<IColor>().Use<Green>(); });
// In a normal Container, a "transient" lifecycle
// Instance will be built up once in every request
// to the Container
container.GetInstance<IColor>()
.ShouldNotBeTheSameAs(container.GetInstance<IColor>());
// From a nested container, the "transient" lifecycle
// is tracked to the nested container
using (var nested = container.GetNestedContainer())
{
nested.GetInstance<IColor>()
.ShouldBeTheSameAs(nested.GetInstance<IColor>());
// One more time
nested.GetInstance<IColor>()
.ShouldBeTheSameAs(nested.GetInstance<IColor>());
}
}
+Instances
scoped to anything but Transient
or AlwaysUnique
are resolved as normal, but through the parent container:
[Fact]
public void nested_container_usage_of_singletons()
{
var container = new Container(_ => { _.ForSingletonOf<IColorCache>().Use<ColorCache>(); });
var singleton = container.GetInstance<IColorCache>();
// SingletonThing's are resolved from the parent container
using (var nested = container.GetNestedContainer())
{
nested.GetInstance<IColorCache>()
.ShouldBeTheSameAs(singleton);
}
}
+See Object Lifecycles for more information on supported object lifecycles.
+A nested container is a new Container object that still retains access to the parent container that created it so that it can +efficiently share registrations, policies, and cached build plans. You can, however, register services into the nested container that override the parent container.
+The FubuMVC web framework uses a nested container per HTTP request. During an HTTP request, FubuMVC injects services +for the current HTTP request and response to a nested container before creating the actual services that will handle the request. The +FubuMVC mechanics are conceptually similar to this code sample:
+
[Fact]
public void overriding_services_in_a_nested_container()
{
var container = new Container(_ =>
{
_.For<IHttpRequest>().Use<StandInHttpRequest>();
_.For<IHttpResponse>().Use<StandInHttpResponse>();
});
var request = new HttpRequest();
var response = new HttpResponse();
using (var nested = container.GetNestedContainer())
{
// Override the HTTP request and response for this
// nested container
nested.Configure(_ =>
{
_.For<IHttpRequest>().Use(request);
_.For<IHttpResponse>().Use(response);
});
var handler = nested.GetInstance<HttpRequestHandler>();
handler.Request.ShouldBeTheSameAs(request);
handler.Response.ShouldBeTheSameAs(response);
}
// Outside the nested container, we still have the original
// registrations
container.GetInstance<IHttpRequest>()
.ShouldBeOfType<StandInHttpRequest>();
container.GetInstance<IHttpResponse>()
.ShouldBeOfType<StandInHttpResponse>();
}
+When handling requests for new services, a nested container first checks its own configuration if it has its own explicit registration for the request. If the nested container does have an explicit registration, it uses that registration. Otherwise, a nested container will attempt to build +an object using the registered configuration of its parent container.
+Nested container object lifecycles equally apply to objects resolved lazily with
+either Lazy<T>
, Func<T>
, or Func<string, T>
as shown below:
public class Foo
{
}
public class FooHolder
{
public IContainer Container { get; set; }
public Func<Foo> Func { get; set; }
public Lazy<Foo> Lazy { get; set; }
public FooHolder(IContainer container, Func<Foo> func, Lazy<Foo> lazy)
{
Container = container;
Func = func;
Lazy = lazy;
}
}
[Fact]
public void service_location_and_container_resolution_inside_nested_containers()
{
var container = new Container();
using (var nested = container.GetNestedContainer())
{
var holder = nested.GetInstance<FooHolder>();
// The injected IContainer is the nested container
holder.Container.ShouldBeTheSameAs(nested);
// Func<T> and Lazy<T> values will be built by
// the nested container w/ the nested container
// scoping
var nestedFoo = nested.GetInstance<Foo>();
holder.Func().ShouldBeTheSameAs(nestedFoo);
holder.Lazy.Value.ShouldBeTheSameAs(nestedFoo);
}
}
+IContainer
object injected above was the nested container that
+created the FooHandler
object. If you do want to use service location within an object, just take in
+IContainer
as a constructor dependency and you will always get the correctly scoped IContainer
.You can created nested containers from profile containers as shown in the sample below:
+
[Fact]
public void nested_container_from_profile_container()
{
var container = new Container(x =>
{
x.For<IColor>().Use<Red>();
x.Profile("Blue", _ => _.For<IColor>().Use<Blue>());
x.Profile("Green", _ => _.For<IColor>().Use<Green>());
});
using (var nested = container.GetProfile("Blue").GetNestedContainer())
{
nested.GetInstance<IColor>().ShouldBeOfType<Blue>();
}
using (var nested = container.GetNestedContainer("Green"))
{
nested.GetInstance<IColor>().ShouldBeOfType<Green>();
}
}
+See Profiles and Child Containers for more information about using profiles.
+As stated above, disposing a nested container will also dispose all objects created with the default Transient lifecycle by the
+nested container that implement the IDisposable
interface. That behavior is demonstrated
+below:
[Fact]
public void nested_container_disposal()
{
var container = new Container(_ =>
{
// A SingletonThing scoped service
_.ForSingletonOf<IColorCache>().Use<ColorCache>();
// A transient scoped service
_.For<IColor>().Use<Green>();
// An AlwaysUnique scoped service
_.For<Purple>().AlwaysUnique();
});
ColorCache singleton = null;
Green nestedGreen = null;
Blue nestedBlue = null;
Purple nestedPurple = null;
using (var nested = container.GetNestedContainer())
{
// SingletonThing's are really built by the parent
singleton = nested.GetInstance<IColorCache>()
.ShouldBeOfType<ColorCache>();
nestedGreen = nested.GetInstance<IColor>()
.ShouldBeOfType<Green>();
nestedBlue = nested.GetInstance<Blue>();
nestedPurple = nested.GetInstance<Purple>();
}
// Transients created by the Nested Container
// are disposed
nestedGreen.WasDisposed.ShouldBeTrue();
nestedBlue.WasDisposed.ShouldBeTrue();
// Unique's created by the Nested Container
// are disposed
nestedPurple.WasDisposed.ShouldBeTrue();
// NOT disposed because it's owned by
// the parent container
singleton.WasDisposed.ShouldBeFalse();
}
+For the sake of clarity, the classes used in the sample above are:
+
public interface IColor
{
}
public class Red : IColor
{
}
public class Purple : Blue { }
public class Blue : IColor, IDisposable
{
public bool WasDisposed;
public void Dispose()
{
WasDisposed = true;
}
}
public class Green : IColor, IDisposable
{
public bool WasDisposed;
public void Dispose()
{
WasDisposed = true;
}
}
public interface IColorCache
{
}
public class ColorCache : IColorCache, IDisposable
{
public bool WasDisposed;
public void Dispose()
{
WasDisposed = true;
}
}
+
+ StructureMap treats simple types like strings, numbers of any kind, enumerations, and dates as primitive +types that are completely exempt from auto wiring -- meaning that any +constructor or setter dependencies on these types must be supplied as inline dependencies.
+To make this concrete, if you ask StructureMap to build a concrete type that has dependencies on simple types without +like this example, StructureMap will throw an exception telling you that it cannot build the instance:
+
public class GuyWithNoDefaultName
{
// StructureMap will not use any kind of auto-wiring
// on name
public GuyWithNoDefaultName(string name)
{
}
}
[Fact]
public void cannot_build_simple_arguments()
{
var container = new Container();
Exception<StructureMapBuildPlanException>.ShouldBeThrownBy(() =>
{
container.GetInstance<GuyWithNoDefaultName>();
});
}
+Part of the exception message thrown in the unit test shown above is the erroneous build plan
+showing you that the name
parameter has to be defined:
+ new GuyWithNoDefaultName(String name) + ┗ String name = Required primitive dependency is not explicitly defined ++
We can build GuyWithNoDefaultName
by supplying a value for name
as I did in the following
+sample:
[Fact]
public void can_build_with_explicit_argument()
{
var container = new Container(_ =>
{
_.ForConcreteType<GuyWithNoDefaultName>()
.Configure.Ctor<string>("name").Is("Steve Winwood");
});
container.GetInstance<GuyWithNoDefaultName>()
.ShouldNotBeNull();
}
+See Construction Policies for an example of using a constructor policy to set a dependency +on a "connectionString" argument in a conventional way.
+As a new feature in the 4.0 release, StructureMap can finally take advantage of default parameter arguments to +derive the values for a primitive argument (or setter value) while still allowing you to explicitly define +that parameter or setter value:
+
// I was listening to Jim Croce's "I've got a Name" song
// when I wrote this feature;)
public class GuyWithName
{
public GuyWithName(string name = "Jim Croce")
{
Name = name;
}
public string Name { get; set; }
}
[Fact]
public void uses_the_default_value_if_one_exists()
{
var container = new Container();
// Should happily build with the default
// value of 'name'
container.GetInstance<GuyWithName>()
.Name.ShouldBe("Jim Croce");
}
[Fact]
public void uses_the_default_value_if_one_exists_2()
{
var container = new Container(_ =>
{
_.ForConcreteType<GuyWithName>();
});
// Should happily build with the default
// value of 'name'
container.GetInstance<GuyWithName>()
.Name.ShouldBe("Jim Croce");
}
[Fact]
public void use_explicit_dependency_if_one_exists()
{
var container = new Container(_ =>
{
_.ForConcreteType<GuyWithName>()
.Configure.Ctor<string>("name").Is("Eric Clapton");
});
container.GetInstance<GuyWithName>()
.Name.ShouldBe("Eric Clapton");
}
+
+ The single best source for information about the particulars of child container behavior is to look through the acceptance tests for child containers and +profiles. +from the code in GitHub.
+The easiest way to explain a child container is to just show it in action:
+
[Fact]
public void show_a_child_container_in_action()
{
var parent = new Container(_ =>
{
_.For<IWidget>().Use<AWidget>();
_.For<IService>().Use<AService>();
});
// Create a child container and override the
// IService registration
var child = parent.CreateChildContainer();
child.Configure(_ =>
{
_.For<IService>().Use<ChildSpecialService>();
});
// The child container has a specific registration
// for IService, so use that one
child.GetInstance<IService>()
.ShouldBeOfType<ChildSpecialService>();
// The child container does not have any
// override of IWidget, so it uses its parent's
// configuration to resolve IWidget
child.GetInstance<IWidget>()
.ShouldBeOfType<AWidget>();
}
+Child Containers are a mechanism to make a completely new Container
that can override some of the parent Container
's registrations but still
+fall back to the parent Container
to fulfill any request that is not explicitly configured to the child container. The behavior of a child container
+in how it resolves services and allows you to override the parent container is very similar to a nested container, but the crucial difference is in how the two concepts handle lifecycles and calling IDisposable.Dispose().
A couple salient facts about child containers that should (knock on wood) dispel the confusion about when and why to use them versus a nested container:
+Profiles were completely redesigned as part of the big 3.0 release.
+Profiles are just named child containers that may be configured upfront through Registry
configurations.
+Profiles are one of the oldest features that date back to the very beginning of StructureMap. Originally profiles were conceived of as
+a way to vary StructureMap registrations by development environment as the code moved from running locally on a developer's box to testing
+servers to production. While that usage is still valid, it is probably more common to use profiles to define overrides for how StructureMap
+should resolve services in different modes of the application (connected vs offline) or different types of system users.
[Fact]
public void Add_default_instance_with_concrete_type()
{
IContainer container = new Container(registry =>
{
registry.Profile("something", p =>
{
p.For<IWidget>().Use<AWidget>();
p.For<Rule>().Use<DefaultRule>();
});
});
var profile = container.GetProfile("something");
profile.GetInstance<IWidget>().ShouldBeOfType<AWidget>();
profile.GetInstance<Rule>().ShouldBeOfType<DefaultRule>();
}
+If you register a new Instance
directly to a child container, that registration is really scoped as a
+singleton within the usage of that particular child container:
[Fact]
public void singletons_to_child_container_are_isolated()
{
var parentContainer = new Container(_ =>
{
_.For<IDependency>().Use<Dependency>();
});
var child1 = parentContainer.CreateChildContainer();
child1.Configure(x =>
{
x.ForSingletonOf<IRoot>().Use<Root>();
});
var child2 = parentContainer.CreateChildContainer();
child2.Configure(x =>
{
x.ForSingletonOf<IRoot>().Use<Root>();
});
// IRoot is a "singleton" within child1 usage
child1.GetInstance<IRoot>().ShouldBeSameAs(child1.GetInstance<IRoot>());
// IRoot is a "singleton" within child2 usage
child2.GetInstance<IRoot>().ShouldBeSameAs(child2.GetInstance<IRoot>());
// but, child1 and child2 both have a different IRoot
child1.GetInstance<IRoot>()
.ShouldNotBeTheSameAs(child2.GetInstance<IRoot>());
}
+It is perfectly valid to create a nested container from a child container for short-lived requests or transactions:
+
[Fact]
public void nested_container_from_child()
{
var parent = new Container(_ =>
{
_.For<IWidget>().Use<AWidget>();
_.For<IService>().Use<AService>();
});
// Create a child container and override the
// IService registration
var child = parent.CreateChildContainer();
child.Configure(_ =>
{
_.For<IService>().Use<ChildSpecialService>();
});
using (var nested = child.GetNestedContainer())
{
nested.GetInstance<IService>()
.ShouldBeOfType<ChildSpecialService>();
}
}
+My shop has been somewhat successful in writing automated integration tests in a whitebox testing style +where we happily "swap out" a handful of external services with a stubbed service that we can happily control +to either setup system state or measure the interaction of our system with the stub (outgoing emails etc) -- with the canonical +example being a web service that our biggest application has to call for authentication purposes that is frequently unavailable during +our development efforts and not quite reliable even when it is available:.
+That's great, and the stubs certainly help the testing efforts be more productive. Until the stateful stubs we inject in one test end up bleeding into +another test as de facto shared state and making those tests fail in ways that were very difficult to diagnose. To combat this problem of test isolation, +we've introduced the idea of using a clean child container per integration test so that the test harness tools can happily +swap in stubs without impacting other tests in the test suite.
+In action, that usage looks something like this:
+
public class TheRealService : IService { }
public class StubbedService : IService { }
[Fact]
public void in_testing()
{
var container = new Container(_ =>
{
_.For<IService>().Use<TheRealService>();
});
// Create a new child container for only this test
var testContainer = container.CreateChildContainer();
// Override a service with a stub that's easier to control
var stub = new StubbedService();
testContainer.Inject<IService>(stub);
// Now, continue with the test resolving application
// services through the new child container....
}
+
+ Nested Containers (Per Request/Transaction)
-TODO(Write some content!)
- + -TODO(Write some content!)
- - -While you can certainly use any IEnumerable
type as a plugin type with your own explicit configuration,
+StructureMap has some built in support for these specific enumerable types:
IEnumerable<T>
IList<T>
List<T>
ICollection<T>
T[]
Specifically, if you request one of these types either directly with GetInstance<IList<IWidget>>()
or as a declared
+dependency in a constructor or setter (new WidgetUser(IList<IWidgets> widgets)
for example) and you have no
+specific registration for the enumerable types, StructureMap has a built in policy to return all the registered instances
+of IWidget
in the exact order that the registrations were made to StructureMap.
Note, if there are not any registrations for whatever T
is, you'll get an empty enumeration.
Here's an acceptance test from the StructureMap codebase that demonstrates this:
+
[Fact]
public void collection_types_are_all_possible_by_default()
{
// NOTE that we do NOT make any explicit registration of
// IList<IWidget>, IEnumerable<IWidget>, ICollection<IWidget>, or IWidget[]
var container = new Container(_ =>
{
_.For<IWidget>().Add<AWidget>();
_.For<IWidget>().Add<BWidget>();
_.For<IWidget>().Add<CWidget>();
});
// IList<T>
container.GetInstance<IList<IWidget>>()
.Select(x => x.GetType())
.ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));
// ICollection<T>
container.GetInstance<ICollection<IWidget>>()
.Select(x => x.GetType())
.ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));
// Array of T
container.GetInstance<IWidget[]>()
.Select(x => x.GetType())
.ShouldHaveTheSameElementsAs(typeof(AWidget), typeof(BWidget), typeof(CWidget));
}
+And another showing how you can override this behavior with explicit configuration:
+
[Fact]
public void override_enumeration_behavior()
{
var container = new Container(_ =>
{
_.For<IWidget>().Add<AWidget>();
_.For<IWidget>().Add<BWidget>();
_.For<IWidget>().Add<CWidget>();
// Explicit registration should have precedence over the default
// behavior
_.For<IWidget[]>().Use(new IWidget[] { new DefaultWidget() });
});
container.GetInstance<IWidget[]>()
.Single().ShouldBeOfType<DefaultWidget>();
}
+One of the ways that I have used the built in IEnumerable
handling is for extensible validation rules. Say that we are
+building a system to process IWidget
objects. As part of processing a widget, we first need to validate that widget with a
+series of rules that we might model with the IWidgetValidator
interface shown below and used within the main
+WidgetProcessor
class:
public interface IWidgetValidator
{
IEnumerable<string> Validate(IWidget widget);
}
public class WidgetProcessor
{
private readonly IEnumerable<IWidgetValidator> _validators;
public WidgetProcessor(IEnumerable<IWidgetValidator> validators)
{
_validators = validators;
}
public void Process(IWidget widget)
{
var validationMessages = _validators.SelectMany(x => x.Validate(widget))
.ToArray();
if (validationMessages.Any())
{
// don't process the widget
}
}
}
+We could simply configure all of the IWidgetValidator
rules in one place with an explicit registration of IEnumerable<IWidgetValidator>
,
+but what if we need to have an extensibility to add more validation rules later? What if we want to add these additional rules in addon packages? Or we
+just don't want to continuously break into the centralized Registry
class every single time we add a new validation rule?
By relying on StructureMap's IEnumerable
behavior, we're able to split our IWidgetValidatior
registration across multiple Registry
classes and that's not infrequently useful to do.
Handling Missing Named Instances
-TODO(Write some content!)
- + -TODO(Write some content!)
- - -The IContext
usage shown in this topic is certainly not going away in future versions of StructureMap, but if at all possible, the StructureMap team
+strongly recommends using Construction Policies to accomplish customized object building instead of relying
+on conditional logic using IContext
at runtime.
The IContext
interface is what StructureMap uses to expose the current state of the internal "build session" for
+the current object creation operation for usage in user-supplied lambda builders or
+interceptors. IContext
allows you to:
Container
to use in a LambdaThe entire IContext
interface is shown below:
public interface IContext
{
string RequestedName { get; }
void BuildUp(object target);
T GetInstance<T>();
T GetInstance<T>(string name);
object GetInstance(Type pluginType);
object GetInstance(Type pluginType, string instanceKey);
T TryGetInstance<T>() where T : class;
T TryGetInstance<T>(string name) where T : class;
object TryGetInstance(Type pluginType);
object TryGetInstance(Type pluginType, string instanceKey);
IEnumerable<T> All<T>() where T : class;
IEnumerable<T> GetAllInstances<T>();
IEnumerable<object> GetAllInstances(Type pluginType);
Type ParentType { get; }
Type RootType { get; }
}
+All of the sample code in this example is in Github.
+One of the canonical examples of using IContext
is the integration of logging frameworks like NLog or Log4net
+that allow you to create logging policies by concrete type. With these tools, you generally have a static class (boo!)
+where you ask for the proper logging service for a type of object like this one:
public static class LoggerFactory
{
public static Logger LoggerFor(Type type)
{
return new Logger(type);
}
}
+Now, say you would want to have the proper Logger
injected into every object that StructureMap creates that depends on Logger
matching
+the concrete type of the object being created. That registration is shown below in a unit test from StructureMap's codebase:
[Fact]
public void can_happily_use_the_parent_type()
{
var container = new Container(x =>
{
// AlwaysUnique() is important so that every object created will get
// their own Logger instead of sharing whichever one is created first
x.For<Logger>().Use(c => LoggerFactory.LoggerFor(c.ParentType)).AlwaysUnique();
});
var top = container.GetInstance<LoggedClass1>();
top.Logger.ParentType.ShouldBe(typeof(LoggedClass1));
top.Child.Logger.ParentType.ShouldBe(typeof(LoggedClass2));
top.Child.Child.Logger.ParentType.ShouldBe(typeof(LoggedClass3));
}
+Just for fun, here's the equivalent with the new construction policies from 4.0:
+
public class LoggerConvention : ConfiguredInstancePolicy
{
protected override void apply(Type pluginType, IConfiguredInstance instance)
{
instance.Constructor
.GetParameters()
.Where(param => param.ParameterType == typeof(Logger))
.Each(param => instance.Dependencies.Add(LoggerFactory.LoggerFor(instance.PluggedType)));
}
}
[Fact]
public void use_logger_convention()
{
var container = new Container(_ =>
{
_.Policies.Add<LoggerConvention>();
});
var top = container.GetInstance<LoggedClass1>();
top.Logger.ParentType.ShouldBe(typeof(LoggedClass1));
top.Child.Logger.ParentType.ShouldBe(typeof(LoggedClass2));
top.Child.Child.Logger.ParentType.ShouldBe(typeof(LoggedClass3));
}
+The LoggerConvention
way of accomplishing the logging integration is technically more code and possibly harder to understand,
+but it's significantly more efficient at runtime because the decision about which Logger
to use is only done once upfront.
+The conventional approach should also be more evident in StructureMap diagnostics.
It's been several years since I used NHibernate, so I might not have the technical details exactly right here:)
+If you're developing a system with NHibernate managed by StructureMap, you will frequently need to inject
+NHibernate's ISession
service into your concrete classes. There's a little catch though, to create an ISession
object
+you have to use NHibernate's ISessionFactory
service:
public interface ISession { }
public interface ISessionFactory
{
ISession Build();
}
+Sidestepping the issue of how to build an ISessionFactory
, here's a possible way to enable a StructureMap
+Container
to build and resolve dependencies of ISession
with a lambda builder:
public class SessionFactoryRegistry : Registry
{
// Let's not worry about how ISessionFactory is built
// in this example
public SessionFactoryRegistry(ISessionFactory factory)
{
For<ISessionFactory>().Use(factory);
// Build ISession with a lambda:
For<ISession>().Use("Build ISession from ISessionFactory", c =>
{
// To resolve ISession, I first pull out
// ISessionFactory from the IContext and use that
// to build a new ISession.
return c.GetInstance<ISessionFactory>().Build();
});
}
}
+
+ Forwarding Requests for a Type to Another Type
-TODO(Write some content!)
- + -