Want an easy way to configure your Inversion of Control (IoC) container using an API? Don’t care one iota about which specific container you actually are using you just want to get the work done? Want to configure your IoC in a type safe manner? Read on and find out how!
Scroll passed the background and rationale musings for the good stuff. ;~)
Background and rationale musings
Looking at a great initiative; the Common Service Locator and using it because it’s a good design practice to use abstractions one can’t help but to hunger for more! There was one more piece I felt myself wanting to sink my teeth into. After some testing, re-working and re-factoring and re-re-factoring ;~) an embryo for a common simple API begun to emerge. We have found in our team that there is a smallish set of classic configuration tasks involved in setting up your IoC:
- Register Instance (with or without a key)
- Register Type (with or without a key)
- Marking a registration a Singleton
- Selecting a constructor for injection
- Selecting properties for injection
This is it really!
Really? Yes pretty much. This is likely to fill about 95% of the needs for configuring an IoC.
We’ve tested it in our project and it works really well. We started out using the API of the IoC we chose but felt it imposed a lot of presence in our code making our coders have to know and care a lot about how and what makes the underlying container tick. All they wanted to do was configure how their code would fit together.
That seems quite easy to create and API for. Indeed. ;~)
But wait; one single API can’t possibly fulfill all of the IoC configuration needs out there for ever! True that – it can’t pretend to be a silver bullet. Well let’s make it easy to extend then.
Hmmm… If not all IoC can implement this API; wouldn’t that make the API a little pointless? Well, not really. The API would not be intended to allow you to replace one container with another without changing or even recompiling the code. Though it could be used that way. Just because you can replace one IoC with another doesn’t mean you will! Having a fitting simplification for an API – and adapter if you will – still makes a lot of sense to your code maintainability!
What if all of the existing IoC creators out there couldn’t care less about this little pesky API? Well I sure can’t blame them who has time to read each and every blog post. Fortunately it doesn’t matter. Let’s make it so that anyone who implements the API for their favorite IoC container and contribute.
That sound’s fair! Not all IoC’s might even have a configuration API for that matter and the ones that do certainly do not have to have one that is suitable for such an API we’re talking of. Besides those that like code abstractions over hard references would use the API because it makes good design sense. Those who don’t care about such things would not use the API.
OK – I’m still interested; let’s have a closer look.
Features we like
What kind of features would we like to have in our API?
- It is annoying when configuration code breaks when you refactor. Type safety?
- It would be nice if it was easy to use and that means easy to read. A fluent interface?
- If I need to add my own favorite feature it should be easy to do so. Open source with an easily extensible API?
- It should be easy to implement for your own IoC. Good use of a base class implementation?
It’s time to look at some sample code for this thing! There is more sample code on the project site and also a listing of the API in full.
This is what the code would look like when you use the API to configure your code; easy to understand, fluent, type safe!
ServiceConfigurator.RegisterType<IFoo, Foo>() .InjectionConstructor(() => new Foo()) .InjectionProperties(f => f.Bar, f => f.Baz) .AsSingleton();
That looks just awesome! Yes indeed! Awesome and quite useful. It’s easy to see how this may be extended for specific purposes. (Doh – sorry I’ll try not to sound like a TV chef or a TV advertisement any more – sorry.)
The code above tells your IoC container that you want to register the implementation Foo as the target for requests for instances of the contract IFoo. It will tell the IoC container to use the parameterless constructor (it can use any constructor). It will also tell the IoC container to use the properties Bar and Baz for Dependency Injection. Finally it will tell the IoC container to treat the instance of Foo as a singleton instance once it is created.
The lambdas look messy! Do they? We don’t even notice any more in our project. They are there to ensure type safety and if you implement this API using the base class the expressions that make up this “mess” are parsed once and for all and converted into more easily handled parameters such as types and strings. If you change any of your configured classes and try to compile the configuration code it will not even compile.
The what and the where
If you feel this API would be pretty darn useful and nice to get your hands on you’re in luck! It’s already created and published under open source license on CodePlex.
So without further ado… Introducing
All the information you need about this project is up there on the site so this post does not need to go any further. If you hurry YOU can contribute with the implementation for your favorite IoC and claim the fame!
If you feel this project is missing one key feature please don’t hesitate to provide feedback!
Thanks to the great guys of coding for the inspirational Common Service Locator project that set our team off in the direction to create a piece of code that extends your work. Together these two pieces of API make our every day much more easy and that is what code by developers and for developers is all about! (The title of this post is a paraphrase from Jeremy Millers classic post.)