Ben Foster
Ben Foster

Reputation: 34800

StructureMap get requested type

Is it possible to pass the requesting type as a parameter when configuring a StructureMap container.

For example:

            container.Configure(x => {
                x.For<ILogger>().Use(new TestLogger(log.Add, requestingType));         
            });

Where requesting type is the consuming object's type:

public class SomeClass
{
    private readonly ILogger logger;
    public SomeClass(ILogger logger)
    {
        this.logger = logger;
    }
}

So the type passed to the logger would be SomeNamespace.SomeClass.

Thanks, Ben

Upvotes: 3

Views: 1327

Answers (3)

Randy Burden
Randy Burden

Reputation: 2661

You can easily gain access to the requested type by using StructureMap's IContext.

ObjectFactory.Configure(
    x => {
        x.For<ILogger>().Use( context => new TestLogger( context.ParentType ) );
    } );

In the above statement, context.ParentType returns the type being created by StructureMap.

Jeremy Miller has covered this topic in a blog post as well. The article uses outdated syntax but it is still relevant: http://codebetter.com/jeremymiller/2009/01/15/using-the-build-session-in-structuremap/

If you would like to inspect all of the available properties in the IContext, you can use an anonymous function and set a breakpoint on the return line like so:

ObjectFactory.Configure(
    x => {
        x.For<ILogger>()
                .Use( context =>
                {
                    // Set breakpoint here and inspect the context
                    return new TestLogger( context.ParentType );
                } );
    } );

Update:

Make sure to use the .AlwaysUnique() ( which is equivalent to the older syntax of .CacheBy( InstanceScope.Unique ) ) otherwise StructureMap will cache the first request of ILogger which will result in the original logger being injected into all subsequent requests for the ILogger during a single GetInstance() call.

This can easily occur if you have nested classes that each require an ILogger so a request for ObjectFactory.GetInstance< ISomeClass >() will result in an ILogger being created for the deepest class in the hierarchy and then all other classes will receive that same instance of ILogger which is most likely what you do not want to happen.

So taking this update and Ben's tip into consideration, here's a better solution:

x.For<ILogger>()
    .AlwaysUnique()
    .Use( c => new TestLogger( c.ParentType ?? c.BuildStack.Current.ConcreteType ) );

Upvotes: 3

Robin Clowers
Robin Clowers

Reputation: 2160

First I want to point out a potential gotcha, registering an instance with Use(new Type()) causes that instance to be registered as a singleton. To avoid this, you can do Use(() => new Type()).

Here is how you get the requested type at configuration time:

container.Configure(x => {
  x.For<ILogger>().Use(c => new TestLogger(log.Add, c.Root.RequestedType));
});

Upvotes: 0

Ben Foster
Ben Foster

Reputation: 34800

I found a solution here

Basically we changed the ILogger interface to ILogger<T> and made use of the generic type inference feature in StructureMap.

Strictly speaking this doesn't answer my question of whether I can get the requesting type so if you know how to do this please respond - it would be useful to know.

Upvotes: 0

Related Questions