четверг, 12 февраля 2015 г.

Declarative IoC container configuration

Nowadays it's hard to develop modern application without using IoC container. Absence of container leads to coupled codebase, expensive and hard to maintain unit tests (and they're not "unit" at all) and, as result, slow development speed and low quality software.

When using IoC container it’s important to ease the process of component and dependency registration and provide enough information to reader (for example during code reviews). While I’m big fan of Convention over Configuration, it doesn't always fit my needs. In applications I develop, I split components into at least 2 categories: components with lifetime bound to lifetime of application and the majority of components with lifetime per operation, such as HTTP request or service bus message. Cache, message bus are examples of former and command handlers, repositories, ApiControllers represent the latter.

Having scope per operation brings the following benefits:
  • Atomicity and isolation. I usually treat this scope as unit of work and try to develop persistence so that result of operation is visible to outer world only after successful completion of operation.
  • Performance and scalability. Each concurrently executing request will have it’s own copy of state, handlers, repositories and so on, avoiding excessive contention. Watch and read Pat Helland’s “Immutability Changes Everything”.
  • Forget about exception safety. Writing exception safe code is hard! It is much easier to throw away scoped container with all it's instances than writing exception safe code.

So it is very important to understand lifetime of the component when reading its code. It helps find mistakes like usage of non thread-safe structures inside long-living class:

[ComponentRegistration(Scope = Lifetime.Application)]
internal sealed class MagicWand : IMagicWand
{
    private HashSet<string> _state = new HashSet<string>();
    // ...
}

As you may understand from this example, I use attribute to specify lifetime of the component. Unfortunately, there are some pitfalls when it comes to building container during application startup. When using Assembly.GetTypes() (or even GetExportedTypes()) on few specific (for example, by file mask) assemblies to discover components with registration attribute, you may occasionally load lot of assemblies which will significantly slow application startup. It may be fine for service running 24/7 that starts once in a while, but desktop application that consists of 3-5 assemblies of “business logic” and 30-50 of UI controls (like Infragistics) will suffer a lot.

This happens, for example, when assembly you’re scanning contains type which derives from type defined in another assembly. The problem can be minimized by moving components not related to DI to separate assembly, but I was looking for better solution. What if generate IoC specific component registrations at compile time?! Roslyn looks like the solution for this and many other problems I have, but I’ve got old proven hammer, which is Text Template Transformation Toolkit or T4.

Check out how I did it for StructureMap, meanwhile I’m going to do the same for my lovely Autofac.
Wider Two Column Modification courtesy of The Blogger Guide