4

I was using a ServiceLocator which i was DIing with Unity

public ServiceLocator(IUserStore userStore, IProdcutsStore productsStore, ...etc) {}

public IUserStore UserStore 
{ 
    get { return userStore; }
}

This all worked fine, but I wanted lazy instantiation of the repositories as they have quite sparse use.

So my ServiceLocator now looks like

    public ServiceLocator(IUnityContainer container) {}

    public IUserStore UserStore 
    { 
        get { return (IUserStore)container.Resolve(typeof(IUserStore)); }
    }

   //  ...etc

I'm now getting a really unhelpful ResolutionFailedException error

Resolution of the dependency failed, type = "DomainModel.DataServices.Interface.IUserStore", name = "". Exception message is: The current build operation (build key Build Key[DomainModel.DataServices.Interface.IUserStore, null]) failed: The current type, DomainModel.DataServices.Interface.IUserStore, is an interface and cannot be constructed. Are you missing a type mapping? (Strategy type BuildPlanStrategy, index 3)

Telling me my interface type cannot be instantiated because it is an interface is pretty pointless. I know it's an interface, that's why the container is supposed to be resolving it for me!

Anyway, the point to note here is that I know the type mapping in the config is fine, as when I was injecting the type interface directly instead of trying to lazy load, it resolved it with no problems.

What am I missing that means something somewhere has to change in order to lazy load this way?

Update: I am guessing what's happening here, is that when I DI the container into the ServiceLocator, the "main" container is instantiating a new container each time which is then not configured properly. I think maybe I need some way to specify that I was to pass this in as the container, rather than resolve it with a new instantiation.

1 Answer 1

3

You're going in a somewhat wrong direction... At first you've had a testable class that declared its dependencies in the constructor and you turned it into non-so-testable, asking for "something" inside a container... No good =(

You should either implement some factory interface for your expensive object and require it in the constructor, or (if you can) switch to Unity 2.0 and use the Automatic Factories:

public ServiceLocator(Func<IUserStore> userStoreBuilder)

//...

public IUserStore UserStore 
{ 
   get { return userStoreBuilder(); }
}

If you want to only create the instance of that object once, you can add cahcing to that property, or with .NET 4.0 you can try asking Lazy in the constructor.

P.S. Oh, yes. And answering your particualr question =) If you still want to inject an instance of your container somewhere else, you need to first register it inside itself =)

container.RegisterInstance<IUnityContainer>(container);

Fix (see comments) DO NOT register a Unity container inside itself, this will cause StackOverflowException in container.Dispose(), the correct instance will be injected as a dependency without the registration.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for this info. I tried to get automatic factories to work for ages this morning, before discovering that Unity cannot inject factories when the dependency have constructor with parameters, which kind of makes it all a bit of a waste of time. You can't do DI if your dependencies also use DI. I think I'm gonna give up with Unity, I've had nothing but problems from the beginning and it's almost impossible to debug. Every minor change in my architecture takes days to get working :(
Are you sure? I thought this Func<T> just wraps a call to container.Resolve<T>... strange...
Dunno... I didn't have many problems with Unity... My colleagues use Autofac and I hear good feedback about it, maybe you should try it.
The container is automatically registered with itself. All you get by calling container.RegisterInstance>(container) is a stack overflow when you do container.Dispose().
@Chris: you're right... I'll update the answer. Thanks a lot!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.