Bricks and Mortar: Building a Castle

Kovacs, James

James Kovacs is an independent architect, developer, trainer, and jack-of-all-trades, specializing in Agile development using the .NET Framework. He is passionate about helping developers create flexible software using test-driven development (TDD), unit testing, object-relational mapping, dependency injection, refactoring, continuous integration, and related techniques. James is a proud member of CodeBetter.com, a Microsoft Most Valuable Professional (MVP)-Solutions Architect, and card-carrying member of ALT.NET, a group of software professionals continually looking for more effective ways to develop applications. He received his Masters degree from Harvard University.

This article was published in:

This article was filed under:

In an application built with object-oriented techniques, objects are the bricks.

You construct little pieces of code encapsulated in these bricks. To build bigger structures, you need to hold these bricks together. You can hardwire them together by instantiating dependent objects within your objects, but it makes the whole structure less flexible in the face of change. So you can adopt an inversion of control (IoC) container to act as your mason to assemble your bricks into complex structures that can flex with changing requirements. In this article, I will examine a popular IoC container, Castle Windsor, and how it enables you to build flexible and robust applications. If you are new to IoC containers and dependency injection, I would recommend reading Martin Fowler's article, Inversion of Control Containers and the Dependency Injection Pattern (http://martinfowler.com/articles/injection.html) and my own article from the March 2008 edition of MSDN Magazine, Loosen Up: Tame Your Dependencies for More Flexible Apps (http://msdn.microsoft.com/en-us/magazine/cc337885.aspx).

IoC Containers perform two basic functions: putting dependencies in and getting fully constructed objects out. I will start by examining how to get fully constructed objects out of your container, and then move on to the more complex aspect of proper configuration of dependencies between objects that you place in the container.

Masonry 101

The first job of a container is to respond to your requests for fully constructed objects by resolving their dependencies and cementing them together for you:

var ap = IoC.Resolve<IAccountsPayable>();

When you ask for an implementation of IAccountsPayable, it is the job of the container to determine which class implements IAccountsPayable, determine the dependencies of this class and any sub-dependencies, and then create instances of all dependencies, building them up as it goes along. You will notice that rather than tying yourself to any particular IoC container, the static gateway pattern is used to decouple the code from a concrete implementation. Let's look at the implementation of IoC. Although IoC is a static class, it forwards all requests to an inner resolver, which is an adapter for the real IoC container:

Notice that IoC and IDependencyResolver do not have any container configuration methods. All the methods (except Initialize()) are devoted to resolving fully constructed objects. You can get dependencies out, but you cannot get dependencies in. This is because containers vary widely on how dependencies are configured in the container. It is the job of the bootstrapper to get the container ready to resolve dependencies in a container-specific way before calling IoC.Initialize().

Let's look at the various ways to get objects out of the container...

Hey, Container, I Need an IAccountsPayable

The most common container lookup is asking the container for the implementer of a particular interface:

var ap = IoC.Resolve<IAccountsPayable>();

You ask the container for the implementer of IAccountsPayable and it returns an object that implements the requested interface. The returned object is ready to perform work for you when you call its methods/properties. Any of AccountsPayable's dependencies have been resolved and satisfied before it is returned to you.

If multiple implementations of IAccountsPayable have been registered in the container, Castle Windsor returns the first one registered. (Note: This is an area where containers differ substantially. Some containers throw an exception if multiple implementations have been registered whereas others return the last implementation registered. Read the container documentation carefully if you are contemplating switching from one IoC container to another and are dependent on this override behavior.)

In the Key of T

Let's say you are integrating multiple databases and access them via IDbGateway implementations. You have an IDbGateway per database registered in the IoC container. How do you get the specific IDbGateway that you are looking for? If you need a specific implementation, you can request it by string-based key:

var gateway =
IoC.Resolve<IDbGateway>(DatabaseKey.Reporting);

where DatabaseKey.Reporting is simply a string constant, "reporting". You can now use this specific implementation to access the Reporting database via the IDbGateway object.

Getting Greedy

What if you need all implementations of a particular interface? I want all registered validators for invoices:

var validators =
IoC.Resolve<IValidator<Invoice>>();

Notice that Castle Windsor can resolve generic interfaces and implementations. You get back all types that are registered as implementing IValidator<Invoice>, but not implementers of IValidator<Customer>. This allows you to write very general code that can validate invoices without tying yourself to a particular set of validation rules. Some of these validation rules may actually be added at run time after the application is deployed!

I Have Something You Might Need

Sometimes you need to supply an externally created instance as a constructor argument. For example, the ASP.NET pipeline creates derived instances of Page. Another example would be WPF creating instances of XAML Pages/Windows. These are your views, which are a dependency of your Presenters/ViewModels. Windsor allows you to supply externally created dependencies as constructor arguments. For example, in the ASPX page's constructor, you would call:

presenter = PresenterFactory.Create
<AccountsPayablePresenter>(this);

Notice that you are passing "this" as the view to the PresenterFactory because you want to wire the Presenter to the view instance (ASPX page) created by the ASP.NET pipeline:

You construct an anonymous type with a property named "view", which matches the name of the constructor argument that you want to supply. You could have also used an IDictionary where the key is the name of the constructor argument. When satisfying dependencies, Windsor will use any registered dependencies as well as any supplied during the call to Resolve<T>() in order to construct an instance of the desired type.

Note: Whether you use anonymous types or keys in an IDictionary to supply externally created constructor arguments, it is your responsibility to ensure that the properties/keys match the names of the constructor arguments. If the constructor arguments are renamed, the corresponding anonymous type property/IDictionary key will not be renamed. Tests for the PresenterFactory (and similar classes) can verify that names match properly.

Getting Dependencies In

You know how to get fully constructed objects out, but how do you get all the dependencies into an IoC container so the container can do its job of constructing objects? Let's look at AccountsPayable. AccountsPayable needs to collaborate with some other objects to get its job done, namely an authorization service, an invoice validator, and an invoice repository. You define your list of dependencies using the AccountsPayable constructor:

This is known as constructor injection. The IoC container will create an instance of AccountsPayable using the above constructor supplying it with instances of the appropriate dependent objects.

Note that if any of AccountsPayable's dependencies had dependencies themselves, the IoC container would find and supply those as well. When wiring dependencies, the container walks the entire dependency graph and creates the dependencies in order from least dependent to most dependent. If a dependency cycle is found (A depends on B depends on A), Castle Windsor will throw an exception.

The Road to Heck Is Paved in Angle Brackets

When Castle Windsor was first introduced, the only means of configuration was XML files. You define a list of components in a file typically called Windsor.config. A component implements a service (aka interface or abstract base class) and is implemented by a concrete type (aka class). Let's take a look at a simple example below:

If you refactor the name of a class or interface or move it to a new namespace or assembly, you have to update Windsor.config appropriately.

Configuring generic services/components requires the CLR generics syntax (e.g., to configure a service, IValidator<Invoice>, you need to use the full CLR type name "JamesKovacs.BricksAndMortar.Services.IValidator`1[[JamesKovacs.BricksAndMortar.Domain.Invoice,JamesKovacs.BricksAndMortar]],JamesKovacs.BricksAndMortar").

Windsor.config is typically quite brittle and can become quite large quickly as you register all your components.

Parlez-vous C#?

The Castle Windsor 2.0 RTM contains another option-fluent configuration in C#. The concept was borrowed from another popular IoC container, StructureMap. Rather than baking IoC configuration in refactoring-hostile XML files, configuration is performed in C# code. The following C# is equivalent to the XML above:

You have solved some of the problems with XML configuration, namely #2, #3, and #4 above. Configuration errors, such as misspelled class/interface names, are now compile-time errors. Since this is C#, refactoring tools can now modify class/interface names, namespaces, and assemblies appropriately when they change. Lastly you can use C# syntax for generics, which you will see more of later.

You still haven't solved problem #1, which is adding a new component requires updating the configuration code, which in this case is in the bootstrapper.

You have introduced a limitation, which is that configuration is now baked into the assembly, thus requiring recompiling the application when you want to make a configuration change. There are a few solutions to this problem. The first option is to accept this limitation, which is potentially a benefit. Do you really want your administrator changing your IInvoiceRepository implementation? A lot of dependencies honestly should be baked into the application. The more knobs you have to turn in your configuration file, the more likely your application is going to be misconfigured. So accept that you want a well-decoupled application so that maintenance/modification is easier, but you don't want to enable this at run time.

For the few dependencies that do need to be tweaked at run time, you can create a hybrid approach combining both XML and fluent configuration. I will investigate this option after I talk about Convention-over-Configuration.

Convention-over-Configuration

Convention-over-Configuration means adhering to a set of application conventions rather than explicitly configuring an application. The idea was popularized in the Ruby community, specifically in Ruby on Rails, which uses the idea to great benefit.

Let's solve problem #1, which is having to maintain the container configuration as new classes/interfaces are added. You are going to use a convention-based approach and the AllTypes class to find all components within an assembly matching a particular criterion:

After finding all the types, you then register the type's first interface as its service. For example, the above code would find the AccountsPayable component and register its first interface, IAccountsPayable, as the service it implements. If you ask the container to resolve IAccountsPayable, it will return an instance of the AccountsPayable class.

WARNING: .NET does not define a strict ordering when implementing interfaces. Although the returned first interface has remained stable since .NET 1.0, there are no guarantees in the future. Generally this isn't a problem because most components implement a single interface.

But you generally don't want to register all types in your assembly. For example, you wouldn't want to register classes like Customer, Order, Address, and such with your IoC container. (If you are familiar with Domain Driven Design, entities and value objects are generally not registered in your container. They are created and consumed by your domain logic.)

Rather than placing classes to be registered in a common namespace, you could use a naming convention instead. For example, if all of your ASP.NET MVC controller classes were post-fixed with Controller (e.g., HomeController, CatalogController, ShoppingCartController, etc.), you could register all of them like this:

The order that you configure the container (XML configuration, then Fluent API, and then Convention-over-Configuration) is important because the first registered component for a service is the one resolved by default. So you need to place any "overrides" in the container first. In the example above, if IReportGenerator is defined in XML configuration, then the Fluent API registered component will not be used. You can change the registration order (i.e., perform XML configuration last) if desired.

You should also avoid registering components twice as component keys must be unique. Later in the article, I will discuss how to override the default component keys if necessary, but it's still good practice to avoid double-registering the same component if only to minimize confusion while debugging.

Alternate Lifestyles

When you ask Windsor to resolve an implementation, the container determines whether an instance of that component has been created previously. If so, it returns this instance. So the following code always succeeds:

Thus you have a single instance of each component in the application. This is the default singleton lifestyle.

The concept of fluent API container configuration was borrowed from another popular IoC container, StructureMap.

Windsor, being the open-minded container that it is, provides a variety of lifestyle options. These include transient, per-thread, per-web-request, and pooled. You can also create your own custom lifestyles if none of the built-in ones satisfy your needs.

No Fixed Address

The transient lifestyle is often used for Presenters or ViewModels in Model-View-Presenter (MVP) or Model-View-ViewModel (MVVM) UI architectures. You do not want multiple views sharing the same Presenter/ViewModel because these objects are orchestrating a specific view. In the case of MVP in classic ASP.NET Web Forms, the views (ASPX pages) are actually requests for different users. Configuring a transient lifestyle enforces an independent instance per view. (In the case of ASP.NET applications, per-web-request might be a more appropriate lifestyle.)

You specify your component's lifestyle when registering it in the container. Using the Fluent API:

Notice that you specify the lifestyle on the component, not on the service. If you have multiple implementers of IAccountsPayablePresenter, the lifestyle is determined by the needs of AccountsPayablePresenter, not the interface that it is implementing.

Have I Got an Instance for You!

Sometimes you don't have control over the instantiation of certain instances, but you would like those instances to participate in dependency resolution. Maybe you are integrating with a third-party framework or are refactoring an existing application to use an IoC container. You need to supply the container with existing instances. You can add instances to the container via the Fluent API:

Note: "localhost" and 25 would typically be read from App/Web.config rather than being hard-coded into the application.

Convention-over-Configuration means adhering to a set of application conventions rather than explicitly configuring an application.

You have taken responsibility for creating the SmtpServer instance, but you can pass the dependency to the controller so other components can utilize the ISmtpServer service provided by this component.

Value Types as Dependencies

Let's take another look at the SmtpServer. What if you want to allow the container to control its lifetime, but you need to provide the host and port as constructor arguments. You can provide dependent parameters to be used in construction in the form of an anonymous type or an IDictionary:

Just as before with supplying constructor arguments during a call to Resolve<T>(), the constructor argument names and anonymous type (or IDictionary key) must match exactly. You should have tests in place to ensure that names match.

A Component by Any Other Name...

If left unspecified (as in the examples above), a component is keyed by its full type name. So if you want to retrieve the IDbGateway instance by key, you would write:

Not only is this overly verbose, but trying to register two DbGateway instances with different connection strings, one for Corporate and one for Reporting, will fail with a duplicate key violation. (Keys in the container must be unique.) You can explicitly specify the key for a component using the Named() method:

Blueprints for the Mason

Sometimes you need to provide the container with some blueprints for building an object. Most often this is because you have registered multiple service implementations and a component needs a particular one. (Relying on Windsor to supply the first one is brittle and you should always specify the dependency's key if there are multiple components for the same service.)

Let's say that you have a ReportGenerator and it needs the IDbGateway to the Reporting database:

Without explicit configuration, if you ask the container for the component implementing IReportGenerator, you would get a ReportGenerator with whichever IDbGateway was registered first in the container. You need to explicitly tell the ReportGenerator the key for the IDbGateway to use via a ServiceOverride:

The ServiceOverride key, dbGateway, is the name of ReportGenerator's constructor parameter and the value is the key for the component that you want to use, in this case DatabaseKey.Reporting. (Note: DatabaseKey.Reporting is a static class containing string constants.)

If you are using Convention-over-Configuration, you can perform the same configuration through Configure()/ConfigureFor<T>():

Open Generic Types

Windsor supports the registration and resolution of open generic types. What is an open generic type? It is a generic class without its type arguments specified. For example, if you have Repository<T>, then Repository<Invoice> is a closed generic type because T is specified as Invoice, whereas Repository<> is an open generic type because T is left unspecified.

You can register closed generic types just as you would any other dependency:

You can now ask the container for IRepository<Invoice>, IRepository<Customer>, IRepository<KitchenSink>, etc. Windsor creates closed generic types on the fly from the open generic type registration!

Notice the slightly different syntax in the call to Component.For() where you passed typeof(IRepository<>). The reason is that generic type arguments (the stuff in angle brackets) in C# only accept closed generic types. If you want to specify an open generic type, you need to use the typeof() syntax.

If you are using Convention-over-Configuration via AllTypes, open generic types are located and registered automatically without you having to worry about the details. This is yet another reason to prefer Convention-over-Configuration where possible.

Testing Windsor Configuration

You should have integration tests around your components, which will provide a great deal of confidence that the container is configured correctly. However it is often useful to have a smoke test to quickly verify your container configuration. If you have an IWindsorContainer, you can walk through all registered components and ask the container to resolve (and thus create with all its dependencies) each one:

Notice that you ignore abstract and open generic types. Abstract types, by their very definition, cannot be created. Open generic types could be resolved if you supply appropriate generic constraints. Unless you are using a lot of open generic types, it is often easier to skip them and add additional logic to explicitly resolve them with an appropriate type parameter (i.e., Explicitly call container.Resolve<IRepository<Invoice>>()). You may also want to skip over Presenters or similar components that require external dependencies and write Presenter-specific smoke tests yourself. Still the above simple test will verify the registrations of the majority of your components.

Wrapping It Up

I hope that you have found this brief tour of Castle Windsor informative and have a better understanding of how you can use it for dependency registration and resolution. IoC containers like Windsor provide a solid foundation for keeping your application architecture flexible and robust in the face of ever-changing requirements.

Setter Injection vs. Constructor Injection

Many IoC containers support setter injection as well as constructor injection. With setter injection, the IoC container uses property setters to supply dependencies rather than the constructor. This is useful for optional dependencies. You should prefer constructor injection as you are then guaranteed that your object has all of its required dependencies satisfied, resulting in a lot less null checking. Many popular containers let you freely mix constructor and setter injection as needed.

Kovacs, James

James Kovacs is an independent architect, developer, trainer, and jack-of-all-trades, specializing in Agile development using the .NET Framework. He is passionate about helping developers create flexible software using test-driven development (TDD), unit testing, object-relational mapping, dependency injection, refactoring, continuous integration, and related techniques. James is a proud member of CodeBetter.com, a Microsoft Most Valuable Professional (MVP)-Solutions Architect, and card-carrying member of ALT.NET, a group of software professionals continually looking for more effective ways to develop applications. He received his Masters degree from Harvard University.