IoC, Dll References, and Assembly Scanning

Jeffrey Knight picture Jeffrey Knight · Apr 30, 2009 · Viewed 9.9k times · Source

Although this question is related to StructureMap, my general question is:

When wiring up components with an IoC container in code (as opposed to configuring via xml) do you generally need explicit project/build references to all assemblies?

Why the separate assemblies? Because:


"Abstract classes residing in a separate assembly from their concrete implementations are a great way to achieve such separation." -Framework Design Guidelines p.91


Example:

Let's say I have PersonBase.dll and Bob.dll

Bob inherits from the abstract class PersonBase. They're both in the Person namespace. But in different assemblies.

I'm programming to PersonBase, not Bob.

Back in my main code, I need a person. StructureMap can scan assemblies. Great, I'll ask StructureMap for one!

Now, in my main code, I am of course referring only to PersonBase, not to Bob. I actually don't want my code to know anything about Bob. No project references, no nuthin. That's the whole point.

So I want to say:

//Reference: PersonBase.dll (only)
using Person;  
...

//this is as much as we'll ever be specific about Bob:
Scan( x=> { x.Assembly("Bob.dll"); }

//Ok, I should now have something that's a PersonBase (Bob). But no ?
ObjectFactory.GetAllInstances<PersonBase>().Count == 0

No luck. What does work is being explicit that I want Bob:

//Reference: PersonBase.dll and Bob.dll
using Person; 
...
Scan( x => {x.Assembly("Bob.dll"); }

//If I'm explicit, it works. But Bob's just a PersonBase, what gives?
ObjectFactory.GetAllInstances<Bob>().Count == 1 //there he is!

But now I've had to reference Bob.dll in my project which is exactly what I didn't want.

I can avoid this situation using Spring + Xml configuration. But then I'm back to Spring + Xml configuration ... !

Am I missing something with using StructureMap, or as a general principle, do (fluent) IoC configurations need explict references to all assemblies?

Possibly related question: StructureMap and scanning assemblies

Answer

Jeffrey Knight picture Jeffrey Knight · May 3, 2009

I finally got this sorted out. It looks like this:

IoC Uml http://img396.imageshack.us/img396/1343/iocuml.jpg

with the assemblies

  • Core.exe
  • PersonBase.dll (referenced compile time by Core.exe)
  • Bob.dll (loaded up run time via StructureMap Scan)
  • Betty.dll (loaded up run time via StructureMap Scan)

To get it with StructureMap, I needed a custom "ITypeScanner" to support scanning for assemblies:

public class MyScanner : ITypeScanner {
  public void Process(Type type, PluginGraph graph) {

    if(type.BaseType == null) return;

    if(type.BaseType.Equals(typeof(PersonBase))) {
      graph.Configure(x => 
        x.ForRequestedType<PersonBase>()
        .TheDefault.Is.OfConcreteType(type));
    }
  }
} 

So my main code looks like:

ObjectFactory.Configure(x => x.Scan (
  scan =>
  {
    scan.AssembliesFromPath(Environment.CurrentDirectory 
    /*, filter=>filter.You.Could.Filter.Here*/);

    //scan.WithDefaultConventions(); //doesn't do it

    scan.With<MyScanner>();
  }
));

ObjectFactory.GetAllInstances<PersonBase>()
 .ToList()
  .ForEach(p => 
  { Console.WriteLine(p.FirstName); } );