tags:

views:

431

answers:

1

High Level

With StructureMap, Can I define a assembly scan rule that for an interface IRequestService<T> will return the object named TRequestService

Examples:

  • FooRequestService is injected when IRequestService<FooRequest> is requested
  • BarRequestService is injected when IRequestService<BarRequest> is requested

Details

I have a generic interface defined

public interface IRequestService<T> where T : Request
{
    Response TransformRequest(T request, User current);
}

and then I have multiple Request objects that implement this interface

public class FooRequestService : IRequestService<Foo>
{
    public Response TransformRequest(Foo request, User current) { ... }
}

public class BarRequestService : IRequestService<Bar>
{
    public Response TransformRequest(Bar request, User current) { ... }
}

Now I am at the point where I need to register these classes so that StructureMap knows how to create them because in my controller I want have the following ctor (which I want StructureMap to inject a FooRequestService into)

public MyController(IRequestService<Foo> fooRequestService) { ... }

Right now to get around my issue I have implemented an empty interface and instead of having the FooRequestService implement the generic interface I have it implement this empty interface

public interface IFooRequestService : IRequestService<Foo> { }

Then my controllers ctor looks like so, which works with StructureMaps' Default Convention Scanner

public MyController(IFooRequestService fooRequestService) { ... }

How could I create a rule with StructureMap's assembly scanner to register all objects named TRequestService with IRequestService<T> (where T = "Foo", "Bar", etc) so that I don't have to create these empty Interface definitions?

To throw something else into the mix, where I am handling StructureMap's assembly scanning does not have any reference to the assembly that defines IRequestService<T> so this has to use some sort of reflection when doing this. I scanned the answer to "StructureMap Auto registration for generic types using Scan" but it seems as though that answer requires a reference to the assembly that contains the interface definition.

I am on the path of trying to write a custom StructureMap.Graph.ITypeScanner but I am kind of stuck on what to do there (mainly because I have little experience with reflection).

+1  A: 

You are on the right path with the scanner. Thankfully there is one built into StructureMap. Unfortunately it is not yet, as of this writing, released. Get the latest from trunk and you will see a few new things available within the scanner configuration. An example for your needs is below.

public class MyRegistry : Registry
{
    public MyRegistry()
    {
        Scan(x =>
        {
            x.TheCallingAssembly();
            //x.AssembliesFromApplicationBaseDirectory();
            x.WithDefaultConventions();
            x.ConnectImplementationsToTypesClosing(typeof (IRequestService<>));
        });
    }
}

First you need to tell the scanner configuration which assemblies to include in the scan. The commented AssembliesFromApplicationBaseDirectory() method also might help if you are not doing a registry per assembly.

To get your generic types into the container use ConnectImplementationsToTypesClosing.

For an example on how to setup use registries when setting up the container see: http://structuremap.sourceforge.net/ConfiguringStructureMap.htm

If you like you can skip using registries in general and just do a scan within ObjectFactory.Initialize.

Hope this helps.

KevM
thank you. i will be taking a look at this. currently I am using an assembly scanner, and only 1 registry across all solutions (there is only 1 project in my solution with a reference to StructureMap). 1 issue I am having is that there is a Generic Interface and multiple Impl of that Interface within my UI project but I cannot reference the UI project from within the project with the registry because it would cause a circular reference, which is why I'm hoping to be able to use a scanner.
Jon Erickson