Castle Custom Component Activators

3. February 2009

I have already said here that  I love Castle and how excited I am  about its extensibility. This post will be another one that talks about Castle Microkernel extensibility.

When you try to resolve a component from microkernel, it goes through several steps. It firsts find the appropriate IHandler instance which manages component states and coordinates component creation/destruction that is associated with the service requested. Handler then calls ILifestyleManager in order to get the object requested. The ILifestyleManager manages the lifestyle of the service, and there are several built-in ILifestyleManagers in Castle.

  1. Singleton(Default)
    Only one instance is created and subsequent calls to Resolve method will get the same instance.
  2. Transient
    Every call gets different instance of the service.
  3. PerWebRequest
    A call creates the instance if it is not created for the current web request. Can only be used in ASP.NET environment
  4. Pooled
    Makes a pool of component instance.
  5. Thread
    A call will create the object if it hasn’t been created for that thread. Otherwise, previously created object will be returned.

 

The ILifestyleManager then calls ComponentActivator in order to create object when necessary.

It has been suggested in Castle Development group that NHibernateIntegrationFacility should lazily initialize ISessionFactory. It is really a good idea and it was something that I had in mind but forgot somehow. German offered that a proxy is registered to container and via this proxy this lazy load could be achieved. This was a good idea but I thought there should be a better way in Castle to handle this kind of situation. Then I remembered something called ComponentActivator and even though I didn’t use it previously, its name gave some idea.

Previously the session factory initialized when the NH facility is initialized,

ISessionFactory sessionFactory = cfg.BuildSessionFactory();
Kernel.AddComponentInstance( id, typeof(ISessionFactory), sessionFactory ); 

Instead of this, I created custom ComponentModel that sets the CustomComponentActivator which will be used to create the object instance

var model = new ComponentModel(id, typeof(ISessionFactory), typeof(Empty));
model.LifestyleType = LifestyleType.Singleton;
model.ExtendedProperties[Constants.SessionFactoryConfiguration] = cfg;
model.CustomComponentActivator = typeof (SessionFactoryActivator);
Kernel.AddCustomComponent( model );

I will have access to that ComponentModel in the activator, and since I provide cfg(Nhibernate.Cfg.Configuration) via ExtendedProperties, I’ll be able to initiate the SessionFactory.

public class SessionFactoryActivator : DefaultComponentActivator
{
    public SessionFactoryActivator(ComponentModel model, IKernel kernel,
        ComponentInstanceDelegate onCreation, ComponentInstanceDelegate onDestruction)
        : base(model, kernel, onCreation, onDestruction)
    {

    }
    public override object Create(CreationContext context)
    {
        var configuration = Model.ExtendedProperties[Constants.SessionFactoryConfiguration]
                            as Configuration;
        return configuration.BuildSessionFactory();
    }
}

I really liked this approach that Castle had. I’d like to know if there’s a better of way achieving this specific scenario.

kick it on DotNetKicks.com

, , ,

Castle ServiceIdResolver

19. November 2008

I like Castle, a lot. The thing that I like about it is not only its clean api&design, but also the extensibility points it has.

Sometimes, there are cases when you need to resolve a type that is not registered in the container. Such examples for those cases may be an array of all services of a specific type. An example to this can be found at hammet’s post

This post will be an answer to a question raised in the Castle Project User List.

The question is that he needs his service to be aware of his Id registered in windsor. This is possible with the use of ISubDependencyResolver. Even though this design seems violation of SoC, I believe that it will demonstrate the ISubDependencyResolver well enough.

Tests are first, here they are

public class SampleService1
{
    public SampleService1(string serviceId)
    {
        this.ServiceId = serviceId;
    }
    public string ServiceId { get; set; }
}
public class SampleService2
{
    public SampleService2(string serviceId)
    {
        this.ServiceId = serviceId;
    }
    public string ServiceId { get; set; }
}
public class SampleService3
{
    public SampleService3(int serviceId)
    {
        this.ServiceId = serviceId;
    }
    public int ServiceId { get; set; }
}
public class ServiceIdResolverTests
{
    public ServiceIdResolverTests()
    {
        this.container = new WindsorContainer();
        this.container.Kernel.Resolver.AddSubResolver(new ServiceIdResolver());
        this.container.Register(Component.For<SampleService1>().Named("service1"))
            .Register(Component.For<SampleService2>().Named("service2"))
            .Register(Component.For<SampleService3>().Named("service3"));
    }
    private readonly IWindsorContainer container;

    [Fact]
    public void CanResolveDependencyWithServiceId()
    {
        var s1 = container.Resolve<SampleService1>();
        var s2 = container.Resolve<SampleService2>();
        Assert.Equal("service1", s1.ServiceId);
        Assert.Equal("service2", s2.ServiceId);
        Assert.Throws<HandlerException>(() => container.Resolve<SampleService3>());
    }
}

Now comes to the implementation.

ISubDependencyResolver has 2 simple methods, namely CanResolve and Resolve. CanResolve tells the container that this resolver may handle the operation of resolving and resolve does the real work.

We should define a convention here, about when to resolve a dependency with the service’s id. My convention is if the parameter name is “serviceid”, then this means that the service wants to know about his id.

public class ServiceIdResolver : ISubDependencyResolver
{
    #region ISubDependencyResolver Members
    public bool CanResolve(CreationContext context, ISubDependencyResolver parentResolver,
                            ComponentModel model, DependencyModel dependency)
    {
        return dependency.DependencyKey.ToLowerInvariant().Equals("serviceid") &&
               dependency.TargetType == typeof(string);

    }
    public object Resolve(CreationContext context, ISubDependencyResolver parentResolver,
                            ComponentModel model, DependencyModel dependency)
    {
        return model.Name;
    }
    #endregion
}

In CanResolve method, we tell the container that we are able to resolve a dependency only when it is service id, and in the Resolve method we return that dependency to be the service id.

There are still missing points in the code, we should also check if this parameter is defined somewhere in configuration. If that is the case, we shouldn’t resolve it on our own, but leave the container handles this.

Very easy isn’t it?

kick it on DotNetKicks.com

, , ,