devxlogo

Bricks and Mortar: Building a Castle

Bricks and Mortar: Building a Castle

n 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. But you can adopt an inversion of control (IoC) container that acts as a mason to assemble your bricks into flexible complex structures that adapt easily to changing requirements.

This article examines the popular IoC container “Castle Windsor” to show how it lets you 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 and my own article from the March 2008 edition of MSDN Magazine, Loosen Up: Tame Your Dependencies for More Flexible Apps.

Author’s Note: The concepts in the article are applicable to IoC containers in general, but the code examples use Castle Windsor 2.0 RTM, which is available from The Castle Project. Castle Windsor 2.0 RTM was not officially released when this article was written, but you can download the latest stable build from the Castle Project Build Server (requires a TeamCity login), or retrieve and build latest source code from the Castle Project Subversion Repository. Note that many of the features discussed are not available in Castle 1.0 RC3, so make sure you get Castle Windsor 2.0 RTM.

IoC Containers perform two basic functions: putting dependencies in and getting fully constructed objects out. First, you’ll see how to get fully constructed objects out of a container, and then move on to the more complex aspect of configuring dependencies properly 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. Here’s a typical request:

var ap = IoC.Resolve();

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

public static class IoC {   private static IDependencyResolver resolver;   public static void Initialize(      IDependencyResolver resolver) {      this.resolver = resolver;   }   public static T Resolve(){...}   public static T Resolve(string key){...}   public static T Resolve(object anonType){...}   public static T Resolve(string key,      object anonType){...}   public static IEnumerable ResolveAll(){...}}

At application startup, you bootstrap your chosen IoC (in this case, Castle Windsor) using:

var container = new WindsorContainer();var resolver = new WindsorDependencyResolver(container);IoC.Initialize(resolver);

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 in the way you configure dependencies. It is the job of the bootstrapper to get the container ready to resolve dependencies in a container-specific way before calling IoC.Initialize().

The next sections discuss ways to get objects out of and dependencies into the container.

Editor’s Note: This article was first published in the May/June, 2009 issue of CoDe Magazine, and is reprinted here by permission.

Getting Objects Out of the Container

In this section, you’ll look at the various ways to get objects out of the container.

Hey, Container, I Need an IAccountsPayable

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

var ap = IoC.Resolve();

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 the container returns it to you.

If multiple implementations of IAccountsPayable have been registered in the container, Castle Windsor returns the first one registered.

Author’s 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(DatabaseKey.Reporting);

In this case, 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

Suppose you want all the implementations of a particular interface? For example, I want all registered validators for invoices:

var validators = IoC.Resolve>();

Notice that Castle Windsor can resolve generic interfaces and implementations. You get back all types that are registered as implementing IValidator, but not implementers of IValidator. This lets 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   (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:

public class PresenterFactory {???public static T Create(IView someView) {???   return IoC.Resolve(         new { view = someView });??? }}

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() to construct an instance of the desired type.

Author’s 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? As an example, the AccountsPayable class 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:

public AccountsPayable(   IAuthorizationService authService,   IValidator invoiceValidator,   IInvoiceRepository invoiceRepository) {???   this.authorizationService = authService;???   this.invoiceValidator = invoiceValidator;???   this.invoiceRepository = invoiceRepository;}

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.

Author’s Note: Many IoC containers support setter injection as well as constructor injection. With setter injection, the IoC container uses property setters rather than constructor parameters to supply dependencies, which is useful for optional dependencies. However, you should prefer constructor injection, because it guarantees 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.

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 it finds a dependency cycle (such as A depends on B depends on A), Castle Windsor throws an exception.

The Road to Heck Is Paved in Angle Brackets

When Castle Windsor was first introduced, its 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:

IoC Containers perform two basic functions: putting dependencies in and getting fully constructed objects out.
        

XML configuration suffers from a number of problems:

  1. Adding a new component requires updating Windsor.config.
  2. Configuration errors aren’t caught until run time.
  3. 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.
  4. Configuring generic services/components requires the CLR generics syntax (e.g., to configure a service, IValidator, you need to use the full CLR type name:
JamesKovacs.BricksAndMortar.Services.IValidator1[   [JamesKovacs.BricksAndMortar.Domain.Invoice,      JamesKovacs.BricksAndMortar]],   JamesKovacs.BricksAndMortar.

Windsor.config is typically quite brittle and can become 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, you perform the configuration in C# code. For example, the following C# is equivalent to the preceding XML:

container.Register( ? Component.For()      .ImplementedBy());

That solves 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. Because 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.

However, it still doesn’t solve problem #1, which is that adding a new component requires updating the configuration code, which in this case is in the bootstrapper.

It also introduces a limitation, which is that configuration is now baked into the assembly, thus you must recompile the application to make a configuration change. There are a few solutions to this problem. One is to simply accept the limitation (which is potentially a benefit). Do you really want your administrator changing your IInvoiceRepository implementation? Quite honestly, a lot of dependencies should be baked into the application. The more knobs there are available to turn in configuration files, the more likely that your application will be mis-configured. 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 that combines both XML and fluent configuration. You’ll see more about this option later in this article.

Convention-over-Configuration

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

To solve problem #1?having to maintain the container configuration as new classes/interfaces are added?you can use a convention-based approach and the AllTypes class to find all components within an assembly that match a particular criterion:

container.Register(?? AllTypes      .FromAssembly(Assembly.GetExecutingAssembly())      .Where(type=>type.Namespace.StartsWith(         "JamesKovacs.BricksAndMortar.Services"))      .WithService      .FirstInterface());

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.

Author’s Note: 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.

The Where clause is not required. You could easily make this call:

container.Register( ? AllTypes      .FromAssembly(Assembly.GetExecutingAssembly())      .WithService      .FirstInterface());

But you generally don’t want to register all types in your assembly. For example, you wouldn’t want to register classes such as 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. For example, if all your ASP.NET MVC controller classes were post-fixed with “Controller” (e.g. HomeController, CatalogController, ShoppingCartController, etc.), you could register them all like this:

container.Register( ? AllTypes      .FromAssembly(Assembly.GetExecutingAssembly())      .Where(type=>type.Name.EndsWith("Controller"))      .WithService      .FirstInterface());

All Together Now

Using Convention-over-Configuration does not preclude the use of the Fluent API or XML configuration. You can actually combine any or all of them:

var container =    new WindsorContainer(@".Windsor.config");container.Register( ??Component.For()      .ImplementedBy(), ??AllTypes      .FromAssembly(Assembly.GetExecutingAssembly())      .Where(type=>type.Name.EndsWith("Controller"))      .WithService      .FirstInterface());

The order in which 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, because component keys must be unique. Later in the article, you’ll see 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:

var repo1 = IoC.Resolve();var repo2 = IoC.Resolve();Assert.Same(repo1, repo2);

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 orchestrate 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, you could write:

container.Register(?? Component      .For()      .ImplementedBy()      .LifeStyle.Transient);

Using the Convention-over-Configuration API, the code looks like this:

container.Register( ??AllTypes      .FromAssembly(Assembly.GetExecutingAssembly())      .Where(type=>type.Namespace.StartsWith(         "JamesKovacs.BricksAndMortar.Presenters"))      .WithService      .FirstInterface()      .Configure(c=>c.LifeStyle.Transient));

You can then verify the transient lifestyle of the IAccountsPayablePresenter:

var p1 = IoC.Resolve();var p2 = IoC.Resolve();Assert.NotSame(p1, p2);

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:

var smtpServer = new SmtpServer("localhost", 25);container.Register( ??Component.For()      .Instance(smtpServer));
Author’s Note: “localhost” and “25” would typically be read from App.config or 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:

container.Register( ??Component      .For()      .ImplementedBy()      .DependsOn(         new { host = "localhost", port=25 }));

If you are using Convention-over-Configuration, you can provide additional configuration data to a single component:

container.Register( ??AllTypes      .FromAssembly(Assembly.GetExecutingAssembly())      .Where(type=>type.Namespace.StartsWith(         "JamesKovacs.BricksAndMortar.Services"))      .WithService      .FirstInterface()      .ConfigureFor(         c=>c.DependsOn(         new { host = "localhost", port=25 })));

You can also provide additional configuration data for all components being configured:

container.Register( ??AllTypes      .FromAssembly(Assembly.GetExecutingAssembly())      .Where(type=>type.Namespace.StartsWith(         "JamesKovacs.BricksAndMortar.Services"))      .WithService      .FirstInterface()???   .Configure(c=>c.DependsOn(         new { host = "localhost", port=25 })));

Just as before, in the example that supplied constructor arguments during a call to Resolve(), 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:

var gateway = IoC.Resolve(   "JamesKovacs.BricksAndMortar.Data.DbGateway");

Unfortunately, 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.) To work around this problem, you can explicitly specify the key for a component using the Named() method:

container.Register( ??Component.For()      .ImplementedBy()      .Named(DatabaseKey.Reporting)      .DependsOn(         new { connectionString             = reportingConnectionString }),           Component.For()      .ImplementedBy()      .Named(DatabaseKey.Corporate)      .DependsOn(          new { connectionString               = corporateConnectionString }));

Blueprints for the Mason

Sometimes you need to provide the container with some blueprints for building an object. Usually, 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:

public class ReportGenerator : IReportGenerator {   private readonly IDbGateway dbGateway;????public ReportGenerator(IDbGateway dbGateway) {???   this.dbGateway = dbGateway;?? }}

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 to use the key for the IDbGateway via a ServiceOverride:

container.Register( ? Component.For()      .ImplementedBy()???   .ServiceOverrides(         ServiceOverride.ForKey("dbGateway")      .Eq(DatabaseKey.Reporting)),       ??Component.For()      .ImplementedBy()      .Named(DatabaseKey.Corporate)      .DependsOn(new { connectionString = corpdb }),        ?Component.For()      .ImplementedBy()      .Named(DatabaseKey.Reporting)      .DependsOn(new { connectionString = rptdb }));

The ServiceOverride key, dbGateway, is the name of ReportGenerator’s constructor parameter, and the value is the key associated with 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() or ConfigureFor():

container.Register( ? AllTypes      .FromAssembly(Assembly.GetExecutingAssembly())      .Where(type=>type.Namespace.StartsWith(         "JamesKovacs.BricksAndMortar.Services"))      .WithService      .FirstInterface()      .ConfigureFor(         c=>c.ServiceOverrides(         ServiceOverride.ForKey("dbGateway")      .Eq(DatabaseKey.Reporting))));

Open Generic Types

Windsor supports registration and resolution of open generic types. An open generic type is a generic class without its type arguments specified. For example, if you have a Repository class, then Repository 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:

container.Register( ??Component.For>()      .ImplementedBy>()??);

You could then retrieve this component like this:

var repo = IoC.Resolve>();

However, the following would fail because you had not registered a Repository:

var repo = IoC.Resolve>();

Instead of explicitly registering each closed generic type that you want to use, you can instead register the open generic type:

container.Register(?  Component.For(typeof(IRepository<>))      .ImplementedBy(typeof(Repository<>)));

You can now ask the container for IRepository, IRepository, IRepository, 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(), which passed typeof(IRepository<>). The reason is that generic type arguments (the stuff in angle brackets) in C# accept only closed generic types. If you want to specify an open generic type, you need to use the typeof() syntax.

Author’s Note: When you’re 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 to provide 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:

foreach(var handler in container.Kernel   .GetAssignableHandlers(typeof(object))) {   var impl = handler.ComponentModel.Implementation;?  if(impl.IsAbstract || impl.IsGenericTypeDefinition) {  ??? continue; ??}   container.Resolve(handler.Service);}

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 supplied appropriate generic constraints, but unless you’re using many open generic types, it is often easier to skip them and add additional logic to explicitly resolve them with an appropriate type parameter, such as an explicit call to container.Resolve>(). You might also want to skip over Presenters or similar components that require external dependencies and write Presenter-specific smoke tests yourself. Still, the simple test above will verify the registrations of the majority of your components.

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 such as Windsor provide a solid foundation for keeping your application architecture flexible and robust in the face of ever-changing requirements.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist