I just finished reading Dependency Injection in .NET by Mark Seemann (Amazon link). This is an excellent description of Dependency Injection (DI), the associated patterns, and several of the main DI frameworks. Seemann has pulled together a wide range of resources (books, magazine articles, blog posts) and created a comprehensive work. It is apparent that this is based on a ton of research and personal experience in the DI world.
This turned out to be a good and timely read for me. A couple months ago, I started working on a WPF project using Prism, and Dependency Injection plays a big role in that. A colleague of mine (and former co-worker) highly recommended this book, and so I picked up a copy. (Disclaimer: I am a "book person"; that is how I learn best. Other people have different learning methods, so feel free to take this from a "book person" perspective.)
Part 1 is an overview of Dependency Injection. Seemann describes what DI is, and also dispels some misconceptions about DI. He covers the benefits of DI including late binding, extensibility, parallel development, maintainability, and testability. He also lays a foundation by showing good and bad examples of implementing DI and how each impacts achieving the desired benefits. Finally, he introduces the topics that will be used in the rest of the book, including the design patterns, DI features, and the DI containers that are available.
Part 2 covers the patterns and anti-patterns in DI. The patterns include Constructor Injection, Property Injection, Method Injection, and Ambient Context. Seemann does a good job of covering these patterns including both the benefits and the drawbacks of each. It becomes apparent very quickly that he favors Constructor Injection wherever possible and that the other patterns should be used only when Constructor Injection is not possible. (As a side note: I came to this same opinion in my fairly-short time working with DI.)
The anti-patterns include Control Freak, Bastard Injection, Constrained Construction, and Service Locator. Of these, the Service Locator is the most controversial. Many people consider Service Locator to be a valid DI pattern (rather than an anti-pattern). Seemann himself admits that he promoted the use of Service Locator for many years. He eventually came to the point where the shortcomings of the pattern outweighed the benefits. Prism (the Microsoft Patterns and Practices application guidance) has a service locator baked in (to reference either Unity or MEF for DI out-of-the-box). In my experience with Prism, we have used the service locator pattern, and I can see the benefits and shortcomings. At this point in the project, the scale leans towards the benefits, and we are willing to work with the drawbacks.
Part 2 also has a chapter on "DI Refactorings". This is a very practical review of what types of DI situations you'll run across in the real world -- like dealing with cyclic dependencies and short-lived dependencies. These are great topics to cover. Because the DI containers that we normally work with add the layer of abstraction, sometimes we forget about some potential issues (by assuming that the container is dealing with it).
Part 3 covers some big DI topics: Object Composition, Object Lifetime, and Interception. Object Composition has to do with how we use DI to compose our objects. Seemann shows examples for how to compose objects with various technologies -- from easy implementations with console and WPF applications, to difficult implementations with ASP.NET applications and PowerShell commandlets.
Object Lifetime has to do with how the dependencies themselves are managed. Do you always return the same instance of a dependency no matter who asks for it (Singleton)? Or do you return a new instance of a dependency each time (Transient)? Or do something inbetween? Seemann covers the various lifetimes and the pros and cons for each. As with everything, we need to consider our particular situation and select the right answer for the task at hand.
Finally, Seemann covers Interception. This is the idea of using the DI container to inject cross-cutting concerns into our application. For example, we could have the container inject logging or error handling into each of our dependencies. This was a very interesting topic to read about. He also covers Aspect Oriented Programming (AOP) and compares/contrasts it with using DI to cover the same concerns.
Part 4 covers several DI containers. What I really liked about this section is that Seemann uses the same examples in each chapter. This means that instead of focusing on the example itself, we can focus on the differences in the container implementations. The containers covered are not exhaustive (5 containers), but they are some of the most widely-used ones.
The containers include Castle Windsor, StructureMap, Spring.NET, Autofac, and Unity. Using each container, examples cover configuration, managing lifetime, interception, and how working with difficult APIs (the difficult APIs refers to the dependencies that we are registering/resolving, not the container APIs themselves). Not all containers support all features out-of-the-box, and Seemann shows some possible work-arounds for the features that are not implemented directly by the container. The end result is that most of the containers work pretty much the same (which is good), but there are slight variations. The container you select can be based on personal preference or particular needs (for example Spring.NET is actually a much larger framework that includes DI functionality; you may want to use Spring.NET for those other features or because you also use Spring in the Java world).
Lastly, Part 4 covers MEF (Managed Extensibility Framework). While MEF is not a DI container, it is often used for DI purposes. (This is true of the Prism framework -- it supports using MEF as a DI container.) Seemann shows that while MEF can be used for DI, it probably should not be. Again, this is a controversial topic: I have seen blog articles where people moved from Unity to MEF for DI and see no reason why anyone would want to start a new project with Unity. Seemann lays out some very good points regarding how DI is implemented using MEF and how it varies greatly from the other containers.
Where Dependency Injection in .NET really shines is in its use of external references. Many sections point to books, magazine articles or blog articles where you can research topics further. Seemann has gone to a lot of work to collect these resources together in one place. I will be spending a lot of time going through the links collected at the back of the book. On a good note (personally), I found that several of the books mentioned are already in my collection.
Dependency Injection in .NET is an excellent resource. There are not very many DI books on the market, and it is great to see that this particular book is so well executed. I would recommend this to any developer who is interested in improving his/her use of Dependency Injection.