Design - Where Should Objects Be Registered When Using Windsor

Design - Where should objects be registered when using Windsor

In general, all components in an application should be composed as late as possible, because that ensures maximum modularity, and that modules are as loosely coupled as possible.

In practice, this means that you should configure the container at the root of your application.

  • In a desktop app, that would be in the Main method (or very close to it)
  • In an ASP.NET (including MVC) application, that would be in Global.asax
  • In WCF, that would be in a ServiceHostFactory
  • etc.

The container is simply the engine that composes modules into a working application. In principle, you could write the code by hand (this is called Poor Man's DI), but it is just so much easier to use a DI Container like Windsor.

Such a Composition Root will ideally be the only piece of code in the application's root, making the application a so-called Humble Executable (a term from the excellent xUnit Test Patterns) that doesn't need unit testing in itself.

Your tests should not need the container at all, as your objects and modules should be composable, and you can directly supply Test Doubles to them from the unit tests. It is best if you can design all of your modules to be container-agnostic.

Also specifically in Windsor you should encapsulate your component registration logic within installers (types implementing IWindsorInstaller) See the documentation for more details

How to register separate instance of a class using Windsor Container

In your code lifestyle of PgDataAccess is singleton, since "Singleton is the default lifestyle, which will be used if you don't specify anyone explicitly"

So, your code is similar to

_windsorContainer.Register(Component.For<PgDataAccess>()
.LifestyleSingleton()
.UsingFactoryMethod(() =>
{
var dataAccess = new PgDataAccess();
dataAccess.ConnectionString = connectionString;
return dataAccess;
}));

If you want to have new instance of PgDataAccess for each component that depends on it, you should register it as transient.

_windsorContainer.Register(Component.For<PgDataAccess>()
.LifestyleTransient()
.UsingFactoryMethod(() =>
{
var dataAccess = new PgDataAccess();
dataAccess.ConnectionString = connectionString;
return dataAccess;
}));

You can read more information about lifestyles here.

how to install dependencies with castle windsor in a layered architecture

How about this. The downside is that you need to hardcode the Name of your repository dll, but you could always move this to web.config etc which would be slightly cleaner.

IWindsorContainer container = new WindsorContainer();

// Register repositories
_container.Register(
AllTypes.Pick()
.FromAssemblyNamed("MyDataLayerAssembly")
.WithService
.DefaultInterface());

// Register services
_container.Register(
AllTypes.Pick()
.FromAssemblyNamed(typeof(ISomeService).Assembly.GetName().Name)
.WithService
.DefaultInterface());

ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));

You may just need to tweak precisely what's passed into the Register() methods to suit your needs however.

Castle Windsor: How do I inject all implementations of interface into a ctor?

You have to use CollectionResolver. Check this Castle Windsor FAQ:

Windsor, by default when you have dependency on IFoo[],
IEnumerable or IList will check if you have a component
registered for that exact type (array or list of IFoo), not if you
have any components registered for IFoo (array of components, is not
the same as a component which is an array). You can change the
behavior to say "When you see array or list of IFoo just give me all
IFoos you can get" you use CollectionResolver.

Direct link to Castle Resolvers: Resolvers.

Can't register Castle Windsor components by convention

You are not specifying any service that are registered by your classes, so by default the classes are registered as services to themselves. From the documentation:

By default the service of the component is the type itself

You must specify what services the component is registered against; you do that using the WithService property or shortcut functions (WithServiceBase(), WithServiceDefaultInterfaces(), etc). The linked resource contains the different selections methods you can use:

  • Base
  • DefaultInterfaces
  • FromInterface
  • AllInterfaces
  • Self
  • Select

Krzysztof Kozmic is recommending that you register your components using the Base service, which you would do like this:

container.Register(Classes
.FromThisAssembly()
.BasedOn<IThingey>()
.WithServiceBase()
.LifestyleTransient()
);

How to pass properties from other registered components in castle Windsor

Create a third class Configuration which the others will depend on and put it to the assembly which both are referencing.

container.Register(Component.For<Configuration>())

public class Configuration
{
//your properties
}

public class Foo
{
public Foo(Configuration configuration)
{
}
}

public class Da
{
public Da(Configuration configuration)
{
}
}

List all types registered with a Castle Windsor container instance

Use IKernel.GetAssignableHandlers(typeof(object)):

IWindsorContainer container = ...

foreach (var handler in container.Kernel.GetAssignableHandlers(typeof(object))) {
Console.WriteLine("{0} {1}",
handler.ComponentModel.Service,
handler.ComponentModel.Implementation);
}

Resolving classes without registering them using Castle Windsor

Windsor currently does not support that, and it's by design. The reasoning is that you should explicitly register types you need so that you dont get misconfigured object.

There is however a possibility that there will be added a hook to create non-registered type at some point in the near future, as this is needed by the WCF integration facility. (Edit - it was added in v2.1 - take a look at ILazyComponentLoaders)

Anyway, regardless of lazy component loaders, the best you can do is to use fluent API to batch register all types from an assembly matching your needed criteria upfront. It's not much more code and you'll sleep better at nights.

Use lazy loaders only if you have really not enough information at startup (in your composition root) to determine what components you'll need.

Can delegates be registered with Castle Windsor IOC container?

No need to wrap or subclass functions to register them in Windsor. They work just like any other component. If you need to tell one Func<int> from another, use named components and service overrides, just as with any other component. Example:

[Test]
public void Example() {
var container = new DefaultKernel();
container.Register(Component.For<Func<int>>().Instance(() => 42).Named("42"));
container.Register(Component.For<Func<int>>().Instance(() => 44).Named("44"));
container.Register(Component.For<Something>().DependsOn(ServiceOverride.ForKey("f").Eq("44")));
var s = container.Resolve<Something>();
Assert.AreEqual(44, s.I);
}

class Something {
private readonly int i;
public Something(Func<int> f) {
i = f();
}

public int I {
get { return i; }
}
}

If you're looking to decouple your event registrations using the container, just use the Event wiring facility.



Related Topics



Leave a reply



Submit