StructureMap in multi-layer solution

466 views Asked by At

In my solution I have 3 projects: WebAPI, BusinessLayer and DataLayer.

In WebAPI I have structuremap configured to use a DefaultRegistry:

public class DefaultRegistry : Registry 
{
    public DefaultRegistry() 
    {
        Scan(
            scan => {
                scan.TheCallingAssembly();
                scan.WithDefaultConventions();
            });
        For<Business.Interfaces.IBusinessClass>().Use(ctx => new Business.BusinessClass());
        For<Data.Interfaces.IDataClass>().Use(ctx => new Data.DataClass());            
    }
}

A controller class in WebAPI looks like this:

public class MyController : ApiController
{
    private readonly IBusinessClass _businessClass;

    public MyController(IBusinessClass businessClass)
    {
        _businessClass = businessClass;
    }

    public HttpResponseMessage Get(int id)
    {
        var success = _businessClass.DoSomething();
        return success ? Request.CreateResponse(HttpStatusCode.OK) :   Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Error"); 
    }
}

Injecting dependency for _businessClass in this example works like a charm.

Now let's take a look at the BusinessClass implementation:

public class BusinessClass : IBusinessClass
{
    private readonly IDataClass _dataClass;

    public BusinessClass(IDataClass dataClass)
    {
        _dataClass = dataClass;
    }

    public void DoSomething()
    {
        _dataClass.DoSomethingWithData();
    }
}

In this example dependency injection for _dataClass doesn't work. The dataClass param in the constructor is null so the _dataClass field isn't initialized properly. What am I doing wrong? I'll add that BusinessClass is defined in the BusinessLayer project and DataClass is defined in the DataLayer projects (both of those projects being class libraries).

3

There are 3 answers

0
CSharper On BEST ANSWER

In you're default Registry you are already registering Default Conventions by calling

scan.WithDefaultConventions(); 

So these two calls are redundant.

For<Business.Interfaces.IBusinessClass>().Use(ctx => new Business.BusinessClass());
For<Data.Interfaces.IDataClass>().Use(ctx => new Data.DataClass());   

Like Kenneth said you probably aren't scanning the assembly BusinessClass is located in.

public class DefaultRegistry : Registry 
{
    public DefaultRegistry() 
    {
        Scan(
            scan => {
                scan.TheCallingAssembly();
                scan.AssemblyContainingType<BusinessClass>();
                scan.WithDefaultConventions();
            });            
    }
}
1
Kenneth On

The problem is in your registration:

You're only scanning the calling assembly (which means the Web API project).

You need to include the other assemblies as well (you might need to adjust the names):

Scan(
        scan => {
            scan.TheCallingAssembly();
            scan.Assembly("BusinessLayer");
            scan.Assembly("DataLayer");
            scan.WithDefaultConventions();
        });
0
Sylwester Madej On

I already solved the problem by use Singleton in StructureMap.