Search code examples
c#dependency-injectioninversion-of-controlstructuremap

How Do I Bind Different Concretes to a Property Using StructureMap


They use StructureMap for IoC where I am currently working.

I have an application class that will implement multiple properties of the same interface...and I need to bind DIFFERENT IMPLEMENTATIONS

...and no, I cannot do this: IProvider<T>

FOR INSTANCE:

    public class MyApplication
    {
        [SetterProperty]
        public IProvider OneProvider { get; set; }

        [SetterProperty]
        public IProvider TwoProvider { get; set; }
    }

    public class FooProvider: IProvider {
        // I would like to force this one to bind-on OneProvider ...
    }
    public class BarProvider: IProvider {
        // I would like to force this one to bind-on TwoProvider ...
    }

In Unity, there are many ways to do this, for instance;

[Dependency("FooProvider")]
public IProvider OneProvider { get; set; }

[Dependency("BarProvider")]
public IProvider TwoProvider { get; set; }

...however, StructureMaps SetterProperty attribute doesnt allow for this.

QUESTION:
How do I bind different implementations into an instance-property?

SAMPLE REGISTRY:
Here is an example of what my registry might look like...

public ContainerRegistry()
{
    Scan(
        scan =>
        {
            scan.TheCallingAssembly();
            scan.WithDefaultConventions();
            scan.LookForRegistries();
            scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("My.Awesome.Company", true, null));
            scan.AddAllTypesOf(typeof(IApplication));
            scan.AddAllTypesOf(typeof(IManager<>));
            scan.AddAllTypesOf(typeof(IProvider));
            scan.AddAllTypesOf(typeof(IUnitOfWorkFactory<>));
            scan.SingleImplementationsOfInterface();
        });

    For(typeof(IApplication)).Use(typeof(MyApplication));
} 

Solution

  • Update

    According to documentation, you can use Inline Setter Configuration

    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 MyApplication : IApplication {
        public IProvider OneProvider { get; set; }
        public IProvider TwoProvider { get; set; }
    }
    
    
    public class RuleWithSettersRegistry : Registry {
        public RuleWithSettersRegistry() {
    
            //...other code removed for brevity
    
            For<IApplication>().Use<MyApplication>()
                // I would like to force FooProvider to bind-on OneProvider        
                .Setter(x => x.OneProvider).Is<FooProvider>()
                // I would like to force BarProvider to bind-on TwoProvider
                .Setter(x => x.TwoProvider).Is<BarProvider>();            
        }
    }
    

    Original Answer

    If you are able to modify the implementations and the target class then try to differentiate the intended dependencies.

    public interface IFooProvider : IProvider { }
    
    public interface IFooProvider : IProvider { }
    

    Have the implementations

    public class MyApplication {
        [SetterProperty]
        public IFooProvider OneProvider { get; set; }
    
        [SetterProperty]
        public IBarProvider TwoProvider { get; set; }
    }
    
    public class FooProvider: IFooProvider { }
    
    public class BarProvider: IBarProvider { }
    

    That way when registering all IProvider derived implementations with

    scan.AddAllTypesOf(typeof(IProvider));
    

    it will grab the intended implementations and bind them.