Oct 5, 2010 at 3:34 AM
Edited Oct 5, 2010 at 3:36 AM
I have recently inherited a reasonably young user interface project with my company (previous person resigned).
Without going into too much detail, one of the project goals is to allow injection of content and views of this content from third parties. To achieve this we are building a service oriented framework that uses dependency injection combined with MVVM techniques
and allows people to register their content/views/services during bootstrap and it all magically becomes integrated.
Prism was chosen as primary guidance and in particular the Unity flavor of implementation.
Entering the project at this point I am happy with the technique/technology choices, and do not wish to change them.
The concerns I have at this point is that it appears that (in my opinion) IUnityContainer has been ... abused. It has been injected into just about everything in the framework including base class Views and View Models. It is passed deep into our framework
at a confusingly fine granularity -- and this rings alarm bells for me. Individual declarations (local, properties etc) count over 100, and individual uses count over 300, and the project/product is less than one third complete.
From what I can gather, it is being used in the following (primary) ways:
1. Service Locator (confusingly, Container.Resolve is being used in constructors of classes that also use [Dependency] properties)
2. Object factory (Container.Resolve<ConcreteType>() in order to have its dependencies injected)
3. Injection post construction (MyObject obj = new MyObject(myParameter); Container.BuildUp(obj);)
4. Service Context (Container.CreateChildContainer(), register 'local' services/objects in child, and pass around this 'context' to perform 1., 2. and 3.)
My thoughts on these are:
1. I don't so much mind, but for consistency I would prefer to use either
service locator or dependency injection (personally preferring DI). I don't like that I do not know the object dependencies by looking at it's constructor or properties, instead I need to read the source code (which for a framework is questionable).
2. Conceptually I don't mind, but I would prefer it to be wrapped in some kind of factory which sits on type of DI instead of using the container as a factory. This is fairly easy to achieve with an open generic type mapping of IFactory<> to UnityFactory<>.
3. Problematic, I would like to use a factory, but would prefer not to create a factory for every single type that might take non-DI injected parameters. This appears to be a common challenge on forums I have read. I could create IMyObjectFactory which has
a method Create(myParameter) and then create and instance of UnityMyObjectFactory to allow it to then have DI performed on it, but given the number of types that do this it seems cumbersome and clumsy (as opposed to 2. which is quite clean but only works for
types that do not have non-DI dependencies).
4. This one has really got me stumped. I can appreciate the value of context, and sometimes context with has some kind of hierarchy/inheritance/nesting/recursion (whichever you like), but I am struggling to see the value of creating IUnityContainer contexts
deep inside your application. On a coarse level, I can see some value in a child unity container that holds services specific to a module, but not to any given service/view/viewmodel or indeed object instance. Whats the benefit? I can override a service
at fine granularity, sure, but why? I can't test it. Runtime behavior predictability reduces even more (DI at a course level is enough of a challenge).
My feeling at this point is that IUnityContainer should really only be referenced from the Bootstrapper and most likely and Module that requires integration, but extracting/replacing IUnityContainer with other suitable patterns appears to be quite painful
unless I can figure a reasonably generic way to solve 3. and 4.
So this is a call out to some seasoned Prism/Unity veterans.
Are my gut feelings valid?
Which usages sound reasonable and which do not and why?
What recommendations can anyone offer at this point to help me move forward?
A thousand thanks,