Fork me on GitHub

Using the Container Model Edit on GitHub


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.

Querying for Plugin Types

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));

Working with a Plugin Type

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.

Finding the Default for a Plugin Type

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));

Finding an Instance by Type and Name

Use this syntax to find information about an Instance in a given plugin type and name:


var redRule = container.Model.Find<Rule>("Red");

All Instances for a Plugin Type

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

Ejecting Services and/or Configuration

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));

Testing for Registrations

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();

Finding all Possible Implementors of an Interface

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.

Working with Individual Instances

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;