18 May
2008

Integrating Castle Windsor and NHibernate with WCF

Category:UncategorizedTag: , :

Up until now, we were using the NHibernate facility of Castle Windsor for managing our NHibernate sessions in WCF. But, we want to have a session-per-request approach as one would use when integrating NHibernate with a regular web application.

Yesterday I did a small spike to figure out how this should work. It turned out to be pretty easy. I used this excellent blog post written by Oran Dennison as my guide.

First I created a class that implemented the IServiceBehavior interface.

public class DIServiceBehavior : IServiceBehavior { private readonly ISessionFactory _sessionFactory; public DIServiceBehavior() { _sessionFactory = new Configuration() .Configure() .BuildSessionFactory(); XmlConfigurator.Configure(); // Log4Net } public void ApplyDispatchBehavior( ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { foreach(ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers) { ChannelDispatcher cd = cdb as ChannelDispatcher; if(cd != null) { foreach(EndpointDispatcher ed in cd.Endpoints) { ed.DispatchRuntime.InstanceProvider = new DIInstanceProvider (serviceDescription.ServiceType, _sessionFactory); } } } } public void AddBindingParameters( ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } }

The SessionFactory is created in the constructor because the ApplyDispatchBehaviour method can be called multiple times (for each endpoint).

The next step is to create an instance provider by creating a class that implements the IInstanceProvider:

public class DIInstanceProvider : IInstanceProvider { private const String NHibernateSessionKey = "NHibernate.Session"; private readonly Type _serviceType; private IDependencyContainer _dependencyContainer; private readonly ISessionFactory _sessionFactory; private ISession _session; public DIInstanceProvider(Type serviceType, ISessionFactory sessionFactory) { Debug.Assert(null != serviceType, "null != serviceType"); _serviceType = serviceType; Debug.Assert(null != sessionFactory, "null = sessionFactory"); _sessionFactory = sessionFactory; } public Object GetInstance(InstanceContext instanceContext) { return GetInstance(instanceContext, null); } public Object GetInstance(InstanceContext instanceContext, Message message) { _dependencyContainer = new DependencyContainer(); _session = _sessionFactory.OpenSession(); _dependencyContainer .AddComponentInstance(NHibernateSessionKey, _session); return _dependencyContainer.Resolve(_serviceType); } public void ReleaseInstance(InstanceContext instanceContext, Object instance) { if(null != _session) { _session.Close(); _session = null; } if(null != _dependencyContainer) { _dependencyContainer.Dispose(); _dependencyContainer = null; } } }

I created a wrapper class around for Castle Windsor named DependencyContainer.  The GetInstance method opens a new session using the SessionFactory object we instantiated in the service behavior class. The session object is then registered with Castle Windsor. We can now implement our repositories like this:

public class SomeAggregateRepository { private ISession _session; public SomeAggregateRepository(ISession session) { _session = session; } public SomeAggregate Get(Int64 id) { return _session.Get<SomeAggregate>(id); } }

When our service operation has been executed, the NHibernate is released by the ReleaseInstance method. Finishing our example, we need to implement a custom ServiceHost and a ServiceHostFactory:

public class DIServiceHost : ServiceHost { public DependencyInjectionServiceHost() : base() { } public DIServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) { } protected override void OnOpening() { Description.Behaviors.Add(new DIServiceBehavior()); base.OnOpening(); } } public class DIServiceHostFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost( Type serviceType, Uri[] baseAddresses) { return new DIServiceHost(serviceType, baseAddresses); } }

The custom ServiceHostFactory class can now be used in the ServiceHost file required when doing IIS hosting:

<%@ ServiceHost Language="C#" Debug="true" Service="WindsorService.MyWindsorService" Factory="WindsorService.DIServiceHostFactory" CodeBehind="MyWindsorService.svc.cs" %>

There is also another way for achieving this that I will be investigating the next week or so using the WCF Integration Facility for Castle Windsor. For some reason it is not available in the current release of the Castle stack so I have to grab it from the trunk.

If you have any thoughts, improvements or suggestions I’m glad to hear them from you, my dear reader. It’s the only way I’ll ever learn :-).

Till next time.

10 thoughts on “Integrating Castle Windsor and NHibernate with WCF

  1. Nice example, but very frustrating as a novice to both WCF and NHibernate/Windsor. So much detail left out that it makes it difficult to see how all the pieces are interacting.

    Thanks for the start.

  2. Actually, yes please. I’d also like to ask your advice about which versions of the NH / Castle / NHibernate Facility to use.

  3. Jan,
    I also use a similar approach (w/ Unity & EF). When doing some profiling the past few days I noticed that the service itself was not being disposed, even though it implements IDispoable. (I clean up the EF context there)

    It appears when using the IInstanceProvider, ReleaseContext will not Dispose of the service itself. I added the following code, which seems to work well. (w/ a battery of tests, faults, exceptions etc).

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
    //snip…

    var serviceInstance = instance as IDisposable;
    if(serviceInstance != null)
    {
    serviceInstance.Dispose();
    }
    }

    Mem leak no more 😉

  4. Thx for the tip Jarod. My service doesn’t implement an IDisposable so I don’t have that particular problem. I clean up the NH session in the ReleaseInstance method as outlined in the post.

    There’s another I ran into earlier this week regarding concurrency. I’ve willing to put my solution on the blog as soon as I’ve got some time to spare 🙂

Comments are closed.

Find me

RSS
Facebook
Twitter
LinkedIn
SOCIALICON
SOCIALICON

Disclaimer

The opinions and content expressed here are my own and not those of my employer.