Castle Windsor most popular features

In this post I will present the most popular Castle Windsor features encountered in typical enterprise applications.

Source code: https://github.com/marcin-chwedczuk/castle-windsor-most-popular-features

Typed factory

When I follow good software development practices like SOLID I find myself writing plenty of factory classes. These factory classes often fall in one of the two categories:

  • I need to create instance of generic service for specific type e.g. I want to get service that implements ICommandHandler<TCommand> for TCommand type
  • I must pass parameters and/or configuration to the service before I can use it e.g. HeuristicSearch service has quality constructor parameter to decide what solutions are good enough for the user

In cases like these we can use typed factory feature to generate factory implementations:

// to enable typed factory we must add TypedFactoryFacility
// to the container
container.AddFacility<TypedFactoryFacility>();

// case  I: get generic service instance for specific type
public interface ICommandHandler<TCommand> {
    void Handle(TCommand command);
}
public interface ICommandHandlerFactory {
    ICommandHandler<T> Create<T>();
    void Release<T>(ICommandHandler<T> instance);
}
public class AddUserCommandHandler : ICommandHandler<AddUserCommand> {
    public AddUserCommandHandler(/* dependencies */) { ... }
    public void Handle(AddUserCommand command) { ... }
}

container.Register(
    Component.For<ICommandHandler<AddUserCommand>>()
        .ImplementedBy<AddUserCommandHandler>()
        .LifeStyle.Transient,

    // tell Windsor that it should generate factory for me
    Component.For<ICommandHandlerFactory>()
        .AsFactory()
    );

// usage
ICommandHandlerFactory factory =
        container.Resolve<ICommandHandlerFactory>();

ICommandHandler<AddUserCommand> handler =
    factory.Create<AddUserCommand>();

handler.Handle(new AddUserCommand());

factory.Release(handler);

// case II: pass configuration to the service
public interface IGreeter {
    void Greet();
}
public interface IGreeterFactory {
    IGreeter Create(string greeting);
    void Release(IGreeter instance);
}
public class ConsoleGreeter : IGreeter {
    ...
    public ConsoleGreeter(string greeting
        /* you may add other dependencies here,
         * e.g. ITextWrapper wrapper */) { ... }
}

container.Register(
    Component.For<IGreeter>()
        .ImplementedBy<ConsoleGreeter>()
        .LifestyleTransient(),

    // tell Windsor that it should generate factory for me
    Component.For<IGreeterFactory>()
        .AsFactory()
    );

// usage
IGreeterFactory greeterFactory = 
    container.Resolve<IGreeterFactory>();

IGreeter helloWorldGreeter = greeterFactory.Create("hello, world!");
IGreeter goodbyeGreeter = greeterFactory.Create("goodbye cruel world!");

helloWorldGreeter.Greet();
goodbyeGreeter.Greet();

greeterFactory.Release(helloWorldGreeter);
greeterFactory.Release(goodbyeGreeter);

Things to remember when using typed factory:

  • Release method in factory interface is optional.
    It is a good practice to always include Release method in factory interface and to release all instances created using factory when they are no longer needed
  • In case of transient or per-web-request components that are disposable not releasing component will result in a memory leak
  • Remember that some factories should be implemented manually especially these that contain domain knowledge e.g. factory that selects discount strategy based on user profile
Collection resolver

Sometime we want to get all components that provide given service. For example we may try to implement message filtering component and we want to get all components that implement IFilter interface. We may achieve this easily by using Castle Windsor CollectionResolver:

// register CollectionResolver in the container:
container.Kernel.Resolver.AddSubResolver(
        new CollectionResolver(container.Kernel));

// demo:
public interface IFilter {
    bool IsAllowed(string message);
}

public class MessageFilterService {
    private ICollection<IFilter> _filters;

    public MessageFilterService(ICollection<IFilter> filters) {
        this._filters = filters;
    }
    ...
}

container.Register(
    Component.For<MessageFilterService>().LifeStyle.Transient,

    Component.For<IFilter>().ImplementedBy<RejectBazWordFilter>(),
    Component.For<IFilter>().ImplementedBy<FooOrBazFilter>()
);

MessageFilterService service = container.Resolve<MessageFilterService>();
service.IsAllowed("foo");

Since registering CollectionResolver requires a bit of interaction with a container it is advisable to wrap that logic into custom facility:

public class ResolveCollectionsFacility : AbstractFacility {
    protected override void Init() {
        Kernel.Resolver.AddSubResolver(new CollectionResolver(Kernel));
    }
}

// then use:
// container.AddFacility<ResolveCollectionsFacility>();
Component registration using conventions

Convention over configuration is popular subject these days so why not to apply it to the component registration. Instead of writing boring:

Component.For<IFooRepository>()
        .ImplementedBy<FooRepository>()
        .Lifestyle.PerWebRequest,
...
Component.For<IBarRepository>()
        .ImplementedBy<BarRepository>()
        .Lifestyle.PerWebRequest

We may write just once:

Classes.FromThisAssembly()
    .BasedOn(typeof(IRepository<>))
    .WithService.AllInterfaces()
    .Lifestyle.PerWebRequest

Castle Windsor is very flexible when it comes to registering components by convention, we may scan selected assemblies and/or namespaces, we may even select components to register by testing component Type.

PITFALL: Avoid creating conventions based on type name (e.g. register all classes that have names ending with Repository) as much as possible. It is always better to create empty marker interface e.g. IApplicationService and use it to register all necessary components.

Installers

Castle Windsor installers allow us to group component registrations into reusable pieces of code. The real power of installers comes from the fact that we may pass them arguments or in other words we may configure them. For example installer may take a single argument that tells what lifestyle should be applied to all registrations contained in the installer. Such installer can be used in both ASP.NET MVC app when most of the components will be registered as PerWebRequest and in Windows service app where components will be registered as either Transient or Singleton.

Here is example of very simple installer:

public class DummyModuleInstaller : IWindsorInstaller {
    public void Install(IWindsorContainer container, IConfigurationStore store) {
        container.AddFacility<TypedFactoryFacility>();

        // add other installers, facilities etc.

        container.Register(
            Component.For<DummyService>().LifeStyle.Transient
            // other components
            );
    }
}

container.Install(new [] {
    new DummyModuleInstaller()
});
Fallback and default components

When we start grouping registrations into installers often we will find ourselves in situation that we want to register given service only when user of the installer didn’t provide she’s own implementation. We may achieve this by passing parameters to the installer but a fallback components are a better choice here. Components registered as fallbacks will be used by the container only when there is no other component that provides given service:

// fallback is used when no other component
// for service is registered
container.Register(
    Component.For<IFooService>()
        .ImplementedBy<FallbackFooService>()
        .LifeStyle.Transient
        .IsFallback()
        );

Assert.That(container.Resolve<IFooService>(),
    Is.InstanceOf<FallbackFooService>());

// we may register our own component for FooService
container.Register(
    Component.For<IFooService>()
        .ImplementedBy<FooService>()
        );

Assert.That(container.Resolve<IFooService>(),
    Is.InstanceOf<FooService>());

Since word isn’t perfect it happens from time to time that we want to overwrite component registration for some particular service. This usually happens because author of the installer doesn’t use fallback components. But don’t panic Castle Windsor allow us to overwrite service registrations using default components:

container.Register(
    Component.For<IFooService>()
        .ImplementedBy<FooService>());

Assert.That(container.Resolve<IFooService>(),
    Is.InstanceOf<FooService>());

// Without IsDefault() we
// would get an exception telling us that
// there is already component registered for IFooService
// interface.
container.Register(
   Component.For<IFooService>()
       .ImplementedBy<DefaultFooService>()
       .IsDefault()
       );

Assert.That(container.Resolve<IFooService>(),
    Is.InstanceOf<DefaultFooService>());
Interceptors

Interceptors are most powerful Castle Windsor feature that brings power of aspect oriented programming to .NET. Interceptors can be used to implement transaction management, logging, security checks, we may use them to gather performance related statistics and for many other purposes.

Here is a simple interceptor that log the invocations of all component methods:

public class EventTracingInterceptor : IInterceptor {
    public void Intercept(IInvocation invocation) {
        EventTracer.AddEvent("BEFORE " + invocation.Method.Name);

        try {
            // call original method, we may inspect method arguments,
            // generic parameters, return value and many others
            invocation.Proceed();
        }
        finally {
            EventTracer.AddEvent("AFTER " + invocation.Method.Name);
        }
    }
}

[Interceptor(typeof(EventTracingInterceptor))]
public class Service : IService {
    public void Foo() { ... }
    public void Bar() { ... }
}

container.Register(
    // interceptors work only when you expose your
    // components via interfaces.
    // here I registered interceptors by using
    // attributes on Service class but you may also
    // use fluent api.
    Component.For<IService>().ImplementedBy<Service>(),
    Component.For<EventTracingInterceptor>()
    );

IService service = container.Resolve<IService>();
service.Foo();

When you start writing your own interceptors it is generally advisable to create custom attribute e.g. TransactionalAttribute to mark classes that should have interceptors attached. Then you should write your own facility that will scan all components registered in container and will attach interceptor for these marked with your custom attribute. Here is a good example of this approach used to implement caching.

That’s all for today! Thanks for reading.

marcin-chwedczuk

A Programmer, A Geek, A Human