1

So we have ran into what seems like a very common issue with StructureMap and IoC containers in general I assume. Bidirectiona/Circuar dependencies.

Given the following code, it is currently causing a circular dependency since we have it 'autowiring' properties.

public class ServiceA:IServiceA
{
     public IServiceB ServiceBDependency {get;set;}
}

public class ServiceB:IServiceB
{
     public IServiceA ServiceADependency {get;set;}
}

I see the 'dependency' of each of these on eachother, however, I feel that as a property, they are not true dependencies which is what separates them from using constructor injection.

It seems that there should be a way for these services to be resolved...and then have the properties injected after the objects have been created?

I know of various ways to get around this, including the true clean way of rearchitecting my services, but i am curious as to what options I have with instantiation and service registration with StructureMap. It seems like a fairly common issue that would need a solution.

TheJediCowboy
  • 8,924
  • 28
  • 136
  • 208

1 Answers1

0

I'd like to show you my approach. I am using only the setter injection. And we often have many objcets referencing each other, in our web app. E.g. IUserFacade requires IUserState on user creation while IUserState requires IUserFacade on userState deletion (to check for constraint).

e.g.:

public interface IUserFacade
{
   ... // User facade Add, Update, Delete
   IUserStateFacade { set; }    
}
public interface IUserStateFacade
{
   ...
   IUserFacade { set; }
}

In reality, we have many objects with cross references, and even more complicated. And it would really be very costy, if all the referenced objects should be created each time, even if not used during the request. We need the "lazy", the proxy objects to be placed in the setters.

The way how to do it, is a mix of the: 1) StructureMap (IoC top) and 2) Castle (proxying top) libraries. Below I will show some snippets of objects needed for this solution. More could be found inside open source project Catharsis

Wrapper. This object would be injected into each Property by SM (StructureMap) instead of real implementor. It is the sleeping implementation. It is waiting for a first call. If it will never happen (IUserFacade is deleting user, no need to access referenced IUserStateFacade during such request) this wrapper will sleep for ever (request). Once touched, SM will create the real object and Wrapper will pass all calls to that.

The Castle interceptor:

public class Wrapper : IInterceptor
{
    object _lazy;
    protected readonly Type Type;

    public Wrapper(Type type)
    {
        Type = type;
    }

    public void Intercept(IInvocation invocation)
    {
        if (_lazy.IsNull()) // lazily instantiate the instance
        {
            _lazy = ObjectFactory.GetInstance(Type);
        }
        try
        {
            var method = invocation.Method;
            if (method.ContainsGenericParameters)
            {
                method = method.MakeGenericMethod(invocation.GenericArguments);
            }
            invocation.ReturnValue = method.Invoke(_lazy, invocation.Arguments);
        }
        catch (TargetInvocationException ex)
        {
            // PublishingManager.Publish(.... // publish exception
            throw;
        }
    }
}

ProxyInstance. Now, we need an object, clear and understandable to SM. That object will be mapped to all interfaces (IUserFacade...) Instead of returning implementation of the UserFacade.

We can also use our custom AOP filters here.

This ProxyInstance will be provided with the real implementor type, and building up the Wrapper.

The StructureMap Instance:

public class ProxyInstance : Instance { protected readonly ProxyGenerator Factory = new ProxyGenerator(); protected readonly Type ConcreteType;

public ProxyInstance(Type type)
{
    ConcreteType = type; // the type for our Wrapper, the real implementation
}
protected override object build(Type pluginType, BuildSession session)
{
    var aopFilters = 
         // my custom way how to inject more AOP filters
         AopFilterManager.GetFilters()
         // the core for us, one of the interceptors is our Wrapper
        .Union(new[] { new Wrapper(ConcreteType) })
        .ToArray();

    // Castle will emit a proxy for us, but the Wrapper will do the job
    var proxy = Factory
         .CreateClassProxy(ConcreteType, AopFilterManager.AopOptions, aopFilters);

    return proxy;
}

And now just use some standard way how to map it in the SM (I am using custom ProxyConvention but it is out of the scope here). Let's use simplified explicit mapping:

registry
    .For<IUserFacade>()
    .HybridHttpOrThreadLocalScoped()
    .Use(new ProxyInstance(typeof(UserFacade)));
...

Also, each of our objects created via SM, implements IService. So, the default setter injection could be set like this:

registry.SetAllProperties
(
    set => set.TypeMatches
    (
        type => type
            .GetInterfaces()
            .Any(i => i.IsEquivalentTo(typeof(IService)))
    )
);

From that moment, when we need to work with a IUserFacade (the direct ObjectFactory call, or accessed via Wrapper), we recieve the real implementor. All its properties (setter injection) will be pre-populated with our ProxyInstance / Wrapper.

If any of these properties is accessed, e.g. IUserStateFacade the same (discribed above for IUserFacade) will happen again.

  1. Because the Lifecycle is Thread or Request based, we have only one implementor in runtime/web request
  2. Because we do inject the Wrappers while using setter injection, no issues with circular infinite loops. Only the first level is injected each time
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335