Subscribe to the RSS feed then follow me on twitter at @mrlacey (misc) and @wpug (WPDev news)

Wednesday, March 14, 2012

NanoIOC - How I do Depenedency Injection on #WP7

When it comes to Dependency Injection / IOC  there isn't a good story for Windows Phone*.

There's nothing built in and lots of people have created their own solutions. Including, but not limited to,: Funq, MicroIoc, TinyIoc, this or this. But none of them work the way I want to.

I want:
  • Automatic constructor parameter injection
  • Explicit indication of where a dependency exists
  • Explicit configuration of how dependencies should be resolved
  • Fluent configuration

I don't want:
  • Parameter injection
  • Automatic resolving of dependencies
  • An aribtrary ServiceLocator

I don't care about:
  • Letting the container manage singletons
  • Nested/chained dependency resolution

There are two factors which influence my requirements:
1. My past experience with Castle Windsor - Chosen after evaluating what was available at the time (about 4 years or so ago.)
2. My experience with working in development teams where there would always be at least one person who wasn't interested in learning anything new, best practices or, seemingly, code quality. I've learnt that if you're working with such people, or anyone new to the industry, that you'll save yourself a lot of work (in fixing up their errors, mistakes and repeatedly explaining things to them) if everything is explicit and clear and not "magic" because if they can't understand it they can't update it or fix it if there's a problem.


So I've written something myself: http://github.com/mrlacey/NanoIoC

As pointed out in the comments, this doesn't provide automatic constructor injection. Unfortunately the platform just doesn't support a way of doing that. This is my next best thing. - Hope that makes it clearer.

Yes, the name is a tounge-in-cheek reference to MicroIoc & TinyIoC but hints that mine has much less code. (It's less than 90 LOC.)
Yes, I know it's more of a DI framework than an IOC one but the terms are used fairly interchangable out in the real world so I'm happy with this.

How to use it:

For the class that has some external dependencies, we declare this by marking them up with an interface "ISupportInjectionOf<T>". As an example, if we wanted to indicate a page had a dependency up an "IRepository" and an "IDateTimeHelper" we'd do this:

    public partial class MainPage : PhoneApplicationPage,
                                    ISupportInjectionOf<IRepository>,
                                    ISupportInjectionOf<IDateTimeHelper>
    {

Then within our constructor we'd resolve these dependencies:

        private IRepository repository;

        private IDateTimeHelper dateTime;

        public MainPage()
        {
            InitializeComponent();

            repository = this.GetDependency<IRepository>();
            dateTime = this.GetDependency<IDateTimeHelper>();
        }

Yes, we could resolve the dependencies at any time, but in my code it'll always be in the constructors.
This is important for maintaining testability and maintainability. (I'm establishing a convention.)
In the above example I'd also include a constructor overload for directly injecting the dependencies during testing:

#if TEST
        public MainPage(IRepository repo, IDateTimeHelper dateTimeHelper)
        {
            InitializeComponent();

            this.repository = repo;
            this.dateTime = dateTimeHelper;
        }
#endif

Simple!


Configuration:

Configuration is simple and done at app level. We can declare how each dependency should be resolved separately:

    NanoIocConfig.RegisterDependency<IRepository>(new ViewModelRepository());
    NanoIocConfig.RegisterDependency<IDateTimeHelper>(new DateTimeHelper());

Or via a fluent interface:

    NanoIocConfig.RegisterDependency<IRepository>(new ViewModelRepository())
                 .And<IDateTimeHelper>(new DateTimeHelper());


Obviously these examples all use interfaces. But we don't have to. Assuming that we didn't want to hide "DateTimeHelper" behind an interface, we can just do this (note the type is inferred):

    NanoIocConfig.RegisterDependency(new DateTimeHelper());

    dth = this.GetDependency<DateTimeHelper>();

The above examples are all creating an instance to use for every time the dependency is resolved.
Instead, we could pass an instance of a singleton in the traditional way:

    NanoIocConfig.RegisterDependency<IRepository>(ViewModelRepository.Instance);

If you want different instances each time a dependency is resolved simply pass a factory and get the new instances that way.


What do you think?

Useful?
Interesting?
Something you may consider using?
Want it bundled into a NuGet package? (Either as a library or the single source file)

I'd love to know what you think.


* It would be awesome if in a (prefereably near) future version of the Windows Phone SDK, it included tooling to allow it to be easier to implement good development practices in our Windows Phone code. It's awesome that they've made it easy for people to get started with developing for the platform but those beginners need, in time, to know how to write better code and if the tools stop them there's no incentive for them to learn. And for those of us who consider ourselves professionals and do this for a living, we want to be able to apply best practices to our code (work) and not have the SDK and the tooling get in the way and stop us doing basic things.

Are you a Windows Phone, Nokia-X (Android) or Asha developer? If so, you could be getting rewards for the apps you build and the success they achieve by joining the DVLUP program.

6 comments:

  1. You said you wanted automatic constructor parameter injection but I don't see that in NanoIoC.

    ReplyDelete
  2. @Kristof yes, that's what I want but the platform doesn't provide a way of allowing it. This is my next best thing.
    Sorry should have been clearer.

    ReplyDelete
  3. Anonymous1:55 pm

    Have you seen Caliburn.Micro's SimpleContainer and PhoneContainer?

    http://nuget.org/packages/Caliburn.Micro.Container

    //Eddie Garmon

    ReplyDelete
  4. @Eddie Yes I'm aware of Caliburn Micro but it doesn't match exactly what I'm after.

    ReplyDelete
  5. Anonymous4:30 pm

    This comment has been removed by a blog administrator.

    ReplyDelete