kurasa
kurasa

Reputation: 5323

StackoverflowException when using Unity IOC

I am using unity in a Winforms app by injecting the dependency into the constructor of the form (I know this is not best practice) but it does work but I am getting a stackoverflowexception when I am trying to load the mdi form.

is there any way to trace what unity is trying to resolve and somehow find out what is happening?

I have a working example that I know works using this 'design'.

I know this is not an ideal design and I plan on introducing a Presenter down the line but for now this should work and I don't know why it is not

EDIT: I know I have services that reference each other for example

public class Service1(IService2, IService3, IService4):IService1

public class Service2(IService1, IService5):IService2

will this cause an exception?

EDIT2: yes I just created an quick app with this circular reference as listed in my first edit and I got a StackOverflowException - obviously not allowed.

Upvotes: 3

Views: 3967

Answers (1)

tomab
tomab

Reputation: 2151

When you catch the exception in VS go inside it and follow InnerException. Unity should print all registered types and you can see which is missing.

Also look at stack trace. Usually StackOverflow appears when you have circular dependecies like this:

class A { A(B b) { ... } }
class B { B(A a) { ... } }

A depends on B and vice versa. Unity will try to inject in ctor of A a B instance but a B instance needs an A instance which, again, needs a B and so on.

This example is a trivial one but in real work the circularity is harder to spot as there might be a more complex graph of dependencies, between different libraries, like A -> B -> C -> D -> A (where "->" means "depends on").

EDIT Yes, that cross-references services can lead you to a stackoverflow exception if at the moment you're resolving IService1, IService1 itself is not registered yet;

Solution 1 You can bypass this problem if types registration and resolving happens in two steps (rough idea):

  1. Registration register both IService1 and its type and IService2 and its type. This step is doing only registration code and do not process any other things (UI, startup logic, unity resolving, http comms, etc).

  2. Actual application logic starts; now you can resolve anything.

Solution 2

Use empty ctors and doing the resolve inside Service class. You can use RegisterType method to specify that the empty ctor must be called:

container.RegisterType<IServiceProvider, ServiceContainer>(new InjectionConstructor());

Here are more details about circular references with dependency injection using Unity.

Solution 3

Use Lazy<IService> for resolving. Using this the actual resolving will happen on demand, more specific when the first time Lazy.Value property is called first time.

Upvotes: 7

Related Questions