Dependency Injection Inversion in .NET by Mark Seemann
About a week ago Uncle Bob published a post on Dependency Injection Inversion that caused quite a stir in the tiny part of the .NET community I usually pretend to hang out with. Twitter was alive with much debate, but Ayende seems to sum up the .NET DI community's sentiment pretty well:
if this is a typical example of IoC usage in the Java world, then [Uncle Bob] should peek over the fence to see how IoC is commonly implemented in the .Net space
Despite having initially left a more or less positive note to Uncle Bob's post, after having re-read it carefully, I am beginning to think the same, but instead of just telling everyone how much greener the grass is on the .NET side, let me show you.
First of all, let's translate Uncle Bob's BillingService to C#:
public class BillingService { private readonly CreditCardProcessor processor; private readonly TransactionLog transactionLog; public BillingService(CreditCardProcessor processor, TransactionLog transactionLog) { if (processor == null) { throw new ArgumentNullException("processor"); } if (transactionLog == null) { throw new ArgumentNullException("transactionLog"); } this.processor = processor; this.transactionLog = transactionLog; } public void ProcessCharge(int amount, string id) { var approval = this.processor.Approve(amount, id); this.transactionLog.Log(string.Format( "Transaction by {0} for {1} {2}", id, amount, this.GetApprovalCode(approval))); } private string GetApprovalCode(bool approval) { return approval ? "approved" : "denied"; } }
It's nice how easy it is to translate Java code to C#, but apart from casing and other minor deviations, let's focus on the main difference. I've added Guard Clauses to protect the injected dependencies against null values as I consider this an essential and required part of Constructor Injection - I think Uncle Bob should have added those as well, but he might have omitted them for brevity.
If you disregard the Guard Clauses, the C# version is a logical line of code shorter than the Java version because it has no DI attribute like Guice's @Inject.
Does this mean that we can't do DI with the C# version of BillingService? Uncle Bob seems to imply that we can do Dependency Inversion, but not Dependency Injection - or is it the other way around? I can't really make head or tails of that part of the post…
The interesting part is that in .NET, there's no difference! We can use DI Containers with the BillingService without sprinkling DI attributes all over our code base. The BillingService class has no reference to any DI Container.
It does, however, use the central DI pattern Constructor Injection. .NET DI Containers know all about this pattern, and with .NET's static type system they know all they need to know to wire dependencies up correctly. (I thought that Java had a static type system as well, but perhaps I am mistaken.) The .NET DI Containers will figure it out for you - you don't have to explicitly tell them how to invoke a constructor with two parameters.
We can write an entire application by using Constructor Injection and stacking dependencies without ever referencing a container!
Like the Lean concept of the Last Responsible Moment, we can wait until the application's entry point to decide how we will wire up the dependencies.
As Uncle Bob suggests, we can use Poor Man's DI and manually create the dependencies directly in Main, but as Ayende correctly observes, that only looks like an attractive alternative because the example is so simple. For complex dependency graphs, a DI Container is a much better choice.
With the C# version of BillingService, which DI Container must we select?
It doesn't matter: we can choose whichever one we would like because we have been following patterns instead of using a framework.
Here's an example of an implementation of Main using Castle Windsor:
public static void Main(string[] args) { var container = new WindsorContainer(); Program.Configure(container); var billingService = container.Resolve<BillingService>(); billingService.ProcessCharge(2034, "Bob"); }
This looks a lot like Uncle Bob's first Guice example, but instead of injecting a BillingModule into the container, we can configure it inline or in a helper method:
private static void Configure(WindsorContainer container) { container.Register(Component .For<TransactionLog>() .ImplementedBy<DatabaseTransactionLog>()); container.Register(Component .For<CreditCardProcessor>() .ImplementedBy<MyCreditCardProcessor>()); container.Register(Component.For<BillingService>()); }
This corresponds more or less to the Guice-specific BillingModule, although Windsor also requires us to register the concrete BillingService as a component (this last step varies a bit from DI Container to DI Container - it is, for example, redundant in Unity).
Imagine that in the future we want to rewire this program to use a different DI Container. The only piece of code we need to change is this Composition Root. We need to change the container declaration and configuration and then we are ready to use a different DI Container.
The bottom line is that Uncle Bob's Dependency Injection Inversion is redundant in .NET. Just use a few well-known design patterns and principles and you can write entire applications with DI-friendly, DI-agnostic code bases.
I recently posted a first take on guidelines for writing DI-agnostic code. I plan to evolve these guiding principles and make them a part of my upcoming book.
Comments
The *only* difference between the example you give here and how Guice is used is that in Guice you'd annotate the constructor with @Inject, and I don't really buy there being any significant disadvantage to doing so in most cases. I posted in a bit more detail why I don't think the use of @Inject is a problem on my blog yesterday.
If my previous post left the impression that I find Uncle Bob's views justified in the context of Java's DI Containers, that was accidental: I have no opinion on whether or not this is the case as I know too little about the detailed mechanics of Java and the DI Containers available there to have an opinion either for or against.
Whether or not a single annotation constitutes a problem or not ended up warranting an entire new blog post in response :)
I think your code still has the same problem that "Uncle Bob" was trying to solve. If you want a new instance of BillingService from deep in the bowels of the application, you need to reference the container! So, you are creating a dependency on WindsorContainer.
Maybe the solution would be program to an interface instead of depend on a concrete container.
What do you think?
However, explaining how to deal with that will require another blog post - watch this space the next couple of days.
Well, take a dependency on BillingService using standard Constructor Injection. Does this mean that we should have to pass an instance of BillingService through all constructors on the way down? No, rather not.
The answer lies in Aggregate Services. Instead of taking dependencies with the only purpose of passing them on to other dependencies, we can define a more coarse-grained service that encapsulates the desired behavior. This is exactly the kind of scenario where DI Containers excel, because they are able to auto-wire complex object graphs based entirely on their knowledge of which dependencies are required by each concrete type. They can do that when you use Constructor Injection because this knowledge is statically encoded in the type.
Then what if you need BillingService both deep in the bowels of the application as well as near the surface? In most cases I would say that this is a design smell that indicates that the granularity of BillingService is poorly defined. A dependency should be either a fine-grained 'leaf' dependency, or an Aggregate Service - not both.