IUnityContainer a bit too pervasive in samples?

Jul 1, 2008 at 1:39 AM
Hi all,

I'm currently getting up to speed with the Composite WPF project and looking to replace Unity with another DI framework (namely Ninject). Initially I had thought that it would just be a matter of duplicating some of the classes in the UnityExtensions project, ie the Bootstrapper and the ContainerAdapter. Indeed this works fine for an example as simple as HelloWorld and things are up and running in no time.

However, when I try to modify StockTraderRI, I notice that the IUnityContainer is being passed around quite a bit - most modules require a reference to it and so do some controllers. For the cases where it's being used to resolve types in the controller and modules, it's acting more as a Service Locator and it feels to me that it would be cleaner to have these dependencies injected instead of explicitly requiring the DI container to resolve them (OrdersController for example). Now this is fairly easy to fix because the dependencies could just be directly injected in the constructor, or if they're not known at construction, then a specific factory could be injected instead of the DI container itself.

The more complicated cases arise in the module initialization where the module needs to register/bind some types in the DI container. I haven't thought too deeply on this and it would be good to get some feedback as to what a clean solution would be so that the DI container is not required to be passed in to each module directly.

One option would be to expand IContainerFacade a little to allow for the registration of types (with singleton options) - this would be quite easy and solves the vendor dependency, but it still smells a little because the entire container facade would still be being passed around to the modules.

Another option may be to create an IModuleInitializer or IModuleRegistrar interface that gets bound during the module registration in the bootstrapper and passed in to the module constructor for use during Initialize (so we'd have, for example, a UnityNewsModuleRegistrar, a WindsorNewsModuleRegistrar, a NinjectNewsModuleRegistrar, etc). As the bootstrapper is already DI container specific, it's less problematic to do any binding here or to have a specific IModuleRegistrar rely on the container. Then, if the module requires certain objects from the DI container after the registration, it could either call something like IModuleRegistrar.Prepare(this) to have properties injected, or possibly cleaner would be to have factories for the required types passed in to the module constructor, which would be in turn initialized by the IModuleRegistrar ready for creating objects when the module needs them.

One question that arises from this approach is, are we just replacing the module with the module registrar? If all the module is responsible for is type registration, then the answer is yes and it's kind of a moot solution - although I still feel the modules should then technically be called UnityNewsModule, UnityPositionModule, etc.

I would argue though that module initialization is probably made up of a number of steps, of which the DI registration is only one - the rest is the logic around adding views to regions, running controllers, etc. If the DI registration step can be factored out into small, DI-specific registrars, then it makes it much easier to swap one DI implementation for another.

So what do you guys think?

Cheers,

Michael
Jul 1, 2008 at 10:24 AM
At the risk of breaking the space-time continuum, or at the very least occupying compulsive link-followers for a few hours, the NinjectExtensions doodling can be found here. This works for the HelloWorld example and should work for any projects you create from scratch.
Jul 1, 2008 at 7:30 PM
Edited Jul 1, 2008 at 7:49 PM

Hi Michael

Your observations are good ones. Supporting multiple IOC containers was an explict goal from the get-go in Prism. However early on we made a decision that doing so doesn't necessarily equate to the "one container to rule them all." We made the decision that "support" means that at the low-level (our 'framework) none of our apis explicitly depend on one container or another. On the other hand, at the high-level within the application we decided we should not have such an abstraction. The reasoning is very simple. Containers have different semantics and syntaxes.

Part of the reason I choose to use Castle Windsor over Structure Map, NInject, etc is because I like the particular attributes of that container. If I like Structure Map's fluent interface then I want to use that, not some dumbed down abstraction. For this reason we very explicitly use IUnityContainer throughout the RI. We would equally expect if you used NInject then that is what you would use instead. Once I commit to a container, it's unlikely that I would want to change mid-way. However you want to make sure that whatever container you make the decision to use does not block your usage of the patterns and libraries. Now at the core levels, you would need an implementation of IContainerFacade for NInject, and possibly a Bootstrapper if you like the Bootstrapper pattern.

In this way you can use Prism with any container, while at the same time leverage all of the specific benefits each container provides.

As far as the module implementation itself, the reason we inject the container into the module is to allow registration of module-specific types AT load time. This way those types are only registered if the module is loaded. The module is not only used for registering but also instantiating views and controllers. We could have wrapped this with specific services like a ViewService and a ControllerService instead of using the container directly. However, we felt that had the same issues around losing container semantics and such. We could consider this for the future if this is what everyone wants though.

Let us know if this rationale makes sense. Thanks for the feedback!

Jul 2, 2008 at 2:13 AM
Edited Jul 2, 2008 at 5:34 AM
Hi gblock,

The rationale of allowing the modules to register their types at load time makes complete sense - I apologise if my post doesn't make this clear. In fact, most of my post was dedicated to how to solve this particular problem while still allowing the container its semantics - this is actually what I was hoping to get some feedback on.

Based on past experience, many people will assume that the way they see things done in a reference implementation is the way they should be done - ie, that reference implementations represent best practice. For example, OrdersController.StartOrder depends on some presentation models - I don't think I'd be alone in saying it's better practice from a DI perspective to inject these dependencies rather than have OrdersController depend on Unity and have a reference to the container. It may be my lack of knowledge of Unity, but I don't see any "container semantics" being used here, or indeed anywhere in StockTraderRI where types are resolved. In a sense it'd be killing two birds by refactoring this because the code would be clearer (you only see the dependencies you actually need) and it also makes the "support" of multiple DI containers ring a little truer. What better place to show this support than in the tutorials and reference implementation?

Perhaps it's not a good comparison, but I think that ASP.NET MVC is a great example of a platform that provides an easy way to swap one DI container for another.

Now, even if the "container as a service locator" patterns are refactored, there's still the issue of how best to let modules register their dependencies while still allowing each DI container to do it's thing, and it'd be great to hear some thoughts on the ideas that I proposed as I'm sure there's smarter ways to do it. Refactoring out the DI registration from the module initialization into container-specific registrars, while keeping the non-container-specific glue logic is just the first way that popped into my head - and it certainly still allows for whatever container semantics you want because each registrar will be container-specific (just as the bootstrapper is for example).

I guess I just feel that this project is a great way to show best practice for modular WPF apps, or indeed desktop apps in general - and if just a few small changes were made to the module loading process, then DI-agnosticity (?) could be one of those best practices.

I realise for large, complex projects that this may not be achievable - but for the apps included with the release, it's certainly possible (and I would almost say trivial)!

Cheers,

Michael

Edit: Fixed weird font formatting
Jul 3, 2008 at 5:01 AM
Edited Jul 3, 2008 at 5:02 AM
Hi Michael

Thanks for the feedback. In this case having the presentation model in the constructor wouldn't have helped us or we would have done it. OrdersController is a singleton, while the StartOrder method creates a new order screen for each order. As such it needs to resolve a new IOrderPresentationModel instance for each order.

We could have possibly created an OrderPresentationModelFactory which is injected, and then have StartOrder use it for creating the model. We would also need an OrderCompositePresentationModelFactory as well. Before long with this approach we are creating lots of factories unecessarily. I was was talking with Chris Tavares today about this and he had the idea of registering a generic Resolver<T> (he called it Factory) with the container. This would then get the container injected into itself on construction and use it to to resolve specific instances in a clean fashion without requring writing lots of factories by and, and also without requring explicit access to the container. I like the sound of this approach because this way I could inject a Resolver<OrderCompositePresentationModel> and a Resolver<OrderPresentationModel> in the constructor of the controller.

The other place where we use the container directly is at the module level in registering types. This actaully doesn't have to happen in code and can be in config. The downside of one configuration is that those types will all get registered whether the module loads or not...unless we can have the services in config AND have them only registered if the module loads. I've talked to Chris about how we can support this with Unity. You can have a global config file for the contianer, but have sub-configurations within it (1 per module). This would let you have your cake and eat it to on the registration part. This would complement well the Resolver method above that I just described.

I may do a post on this (I say may instead of will since I find I only get a round to a fraction of the thigns i say I will do :) ) 
Jul 3, 2008 at 8:40 AM
Great - that idea regarding the OrdersController is exactly the sort of thing I was hoping for!

In terms of type registration in the modules - I don't necessarily think it has to be in a "config file" as such (not all DI containers support config files), and I certainly wouldn't want it to happen until the module loads.

Unless you're talking about a generic config file that you could write a simple parser for for each DI container, which I guess wouldn't be so bad.

I still wonder though whether the concept of a module bootstrapper, or type register isn't the right way to go.

public interface IModuleBootstrapper
{
public IModule InitializeModule();
}

public class UnityNewsBootstrapper : IModuleBootstrapper
{
protected readonly IUnityContainer container;

public UnityNewsBootstrapper(IUnityContainer container)
{
this.container = container;
// register the types...
}

// This could actually be factored into a base UnityModuleBootstrapper class
public IModule InitializeModule()
{
// Create and inject dependencies into the module
var newsModule = container.Resolve<NewsModule>();
newsModule.Initialize();
return newsModule;
}
}

It would be cleaner to utilise generics, but you get the idea.

Too much effort? Too messy?
Jul 12, 2009 at 7:32 AM

Actually, it would be the best if IContainer or IEventaggr or DI attributes are located under Composite or Composite.Presentation assemblies. The developers who are working on the Module shouldn't use anything related to Unity-specific or UnityExtension specific in their modules. Then, it will be very easy for them to switch the IoC container that they like. 

I'm facing that problem. I'm award of that Prism allows us to switch Ioc containers but I failed to explore how to switch and started using IUnityContainer or a lot of things which are specifc to Unity. Now, I want to try to switch to another IoC container but I couldn't because there are too many dependencies of Unity in my modules. :( 

Jul 12, 2009 at 7:55 AM

Hi Michael

We deliberately did not go to such a level of abstraction when we were desiging Prism. The reasoning was that it was an unnecessary complexity, and it prevents you from being able to take advantage of the full features of the container, as you end up in a least-common-denominator situation. We also believed that if one made the decision to develop an application using a specific container, it was unlikely they would decide to change mid-way.

Glenn

Jul 12, 2009 at 7:57 AM

@mhart what advantage do you think the module registrar woudl buy you?

Sep 29, 2009 at 11:21 PM

This is an interesting discussion, I am currently working on using CAL with Windsor and I've noticed the same thing in the StockTrader app. 

Glenn, I see what you are saying about needing new instances and hence the reference to IUnityContainer.  Still this dependency on the container sprinkled throughout the app feels a bit iffy to me, particularly since UnityContainer is a very different implementation from say WindsorContainer.  I know for my app I will be avoiding having a dependency on IWindsorContainer except in the bootstrapper and IModule classes.

A potential solution that would make the StockTrader implementation more "pluggable" might be to try the following:

1. Only register services in the bootstrapper, or IModule classes (which I believe is already true)

2. Resolve services where necessary using the ServiceLocator or another static container class that provides a Resolve<T>();

This way changing containers can be done simply via a ServiceLocatorAdapter and doesn't require modifying every class that depends on IUnityContainer to work with IWindsorContainer or otherwise.

On a related note, while I can't speak for other IoCs I know that Windsor does not autoregister classes when you call Resolve<Class>() like unity does.  Nor does it default to transient lifestyle behavior.  In it's use of the ServiceLocator the CAL seems to assume this will happen when GetInstance() is called requiring the following adapter implementation:

    protected override object DoGetInstance(Type serviceType, string key){
      if (serviceType.IsClass && !_container.Kernel.HasComponent(serviceType))
        _container.AddComponentLifeStyle(serviceType.FullName, serviceType, LifestyleType.Transient);
      if (String.IsNullOrEmpty(key)) return _container.Resolve(serviceType);
      return _container.Resolve(key, serviceType);
    }

This isn't really a big deal, but it "feels" a bit like a Unity dependency in CAL to me.