Integrating StructureMap and NHibernate with WCF

Following many examples I found online for other IoC containers, I borrowed utilized those designs to create a StructureMap instance provider.  One problem we ran into with that design was dealing with NHibernate.  Mainly, there are two types that are very important to care about when using NHibernate:

  • ISessionFactory
  • ISession

The first type, as the name implies, is responsible for creating the ISession object.  The ISession acts as a Unit of Work, allowing me to execute queries, save entities, and pretty much any other persistence operation with my persistent types.

Typically, in an ASP.NET environment, we’ll follow a Session per Request pattern, and only one ISession object is associated with one request by storing the ISession in HttpContext.Items.  In WCF, configuration of instance contexts and configurable threading makes the picture a little more interesting.  In WCF, we can configure our services to be instantiated as a singleton, per call or per session.  The safest of these three options is per call, as we can be certain on the server side when call-context level items get created and later cleaned up.

There are a few examples of integrating Windsor and NHibernate with WCF, and this solution is inspired by those designs.  Before we get started, let’s create a wrapper for our ISessionFactory and ISession.

Creating the ISessionFactory abstraction

Because ISessionFactory is rather expensive to instantiate, only one of these should be created per application.  Since the ISessionFactory built from the NHibernate Configuration class is thread-safe and meant to be used across threads, we can just make a static reference to it.  The main reason behind an ISessionFactory abstraction is that it’s easier to control lifetime of the ISession we need to provide to our Repository implementations.  This is merely a personal preference, but it makes managing the ISession a little easier.  First, here’s our wrapper interface:

public interface ISessionBuilder
{
    ISession GetSession();
    void CloseSession();
}

We need to both create and close the ISession as part of our Session per Request pattern.  The actual ISessionBuilder implementation isn’t that interesting:

public class SessionBuilder : ISessionBuilder
{
    private static ISessionFactory _sessionFactory;
    private ISession _session;

    public ISession GetSession()
    {
        Initialize();
        if (_session == null)
            _session = _sessionFactory.OpenSession();

        return _session;
    }

    public void CloseSession()
    {
        if (_session == null)
            return;

        _session.Close();
        _session.Dispose();
        _session = null;
    }

    private static void Initialize()
    {
        var sessionFactory = _sessionFactory;
        if (sessionFactory == null)
            _sessionFactory = new Configuration().Configure()
                                    .BuildSessionFactory();
    }
}

When it comes to the repositories that need an ISession, they’ll instead depend on an ISessionBuilder to build the ISession for them:

public class ProductRepository : IProductRepository
{
    private readonly ISessionBuilder _sessionBuilder;

    public ProductRepository(ISessionBuilder sessionBuilder)
    {
        _sessionBuilder = sessionBuilder;
    }

    public Product[] GetExpensiveProducts()
    {
        var session = _sessionBuilder.GetSession();
        var criteria = session.CreateCriteria(typeof(Product));
        criteria.Add(Restrictions.Gt("UnitPrice", 100m));

        var results = criteria.List<Product>();

        return results.ToArray();
    }
}

I like this implementation of finding ISession rather than a service locator or static property, as it fits in well with TDD.  I don’t have to worry about some opaque dependency being up to test my repositories.

Now that we have our ISessionFactory and ISession wrapper in place, let’s look at modifying our original IInstanceProvider.

Modifying the IInstanceProvider

The IInstanceProvider is a WCF extension that allows custom instantiation of the service instance.  Our original StructureMapInstanceProvider used StructureMap’s service locator to build up the service:

public class StructureMapInstanceProvider : IInstanceProvider
{
    private readonly Type _serviceType;

    public StructureMapInstanceProvider(Type serviceType)
    {
        _serviceType = serviceType;
    }

    public object GetInstance(InstanceContext instanceContext)
    {
        return GetInstance(instanceContext, null);
    }

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        return ObjectFactory.GetInstance(_serviceType);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
    }
}

Normally, we wouldn’t have to do anything to this implementation, if only one class depended on ISessionBuilder.  But we want every repository participating in a call to use the exact same ISessionBuilder implementation.  This ensures that everyone uses the same ISession instance in one call.  Otherwise, the Unit of Work and Identity Map would be split amongst each repository, leading to concurrency and identity problems.

What we need is to ensure that for this one call to GetInstance, only one implementation of ISessionBuilder is used.  We can configure caching of the ISessionBuilder implementation, but that won’t allow us to get access to the ISessionBuilder that was used.  In addition to guaranteeing only one instance of ISessionBuilder is used, we need to close and dispose of the ISession at the end of the WCF call.  Instead of using InstanceScope.PerRequest caching in StructureMap, we’ll need to use the With method.

The With method allows us to make a call to the service locator GetInstance, and substitute a specific instance of a dependency during instantiation.  This will allow us to create an instance of the ISessionBuilder, store it for closing later, and use it for the service location of the WCF service instance.  Here’s the new Session per Request instance provider:

public class SessionPerCallInstanceProvider : IInstanceProvider
{
    private readonly Type _serviceType;
    private ISessionBuilder _sessionBuilder;

    public SessionPerCallInstanceProvider(Type serviceType)
    {
        _serviceType = serviceType;
    }

    public object GetInstance(InstanceContext instanceContext)
    {
        return GetInstance(instanceContext, null);
    }

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        _sessionBuilder = ObjectFactory.GetInstance<ISessionBuilder>();

        return ObjectFactory
                .With(_sessionBuilder)
                .GetInstance(_serviceType);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        if (_sessionBuilder != null)
        {
            _sessionBuilder.CloseSession();
            _sessionBuilder = null;
        }
    }
}

In the above WCF extension, WCF will call GetInstance to…get an instance of the service.  Inside that method, we first create an instance of the ISessionBuilder, and store it in a local variable.  Next, we use the With method to tell StructureMap to use that specific instance of ISessionBuilder for the following call to GetInstance.  Adding some debug messages looking at hash codes confirms that the same instance is used here as well in any repositories, at any depth in the dependency graph.  Finally, we add the ReleaseInstance implementation, which closes the ISession at the end of each request.

We’re still not quite finished, we still need to tell WCF to use this instance provider.  For that, we’ll need to create a custom service behavior.

Creating the Session per Request service behavior

In the previous post on using StructureMap to instantiate our service, I used a custom ServiceHostFactory and ServiceHost to attach the StructureMap service behavior at runtime.  This time, I’ll use an attribute instead.  That way, the Session per Request behavior can be opted in for each service implementation by using an attribute.  There’s not much interesting about this service behavior, other than it also inherits from Attribute:

public class SessionPerCallServiceBehavior : Attribute, IServiceBehavior
{
    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 SessionPerCallInstanceProvider(serviceDescription.ServiceType);
                }
            }
        }
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, 
        ServiceHostBase serviceHostBase, 
        Collection<ServiceEndpoint> endpoints, 
        BindingParameterCollection bindingParameters)
    {
    }

    public void Validate(ServiceDescription serviceDescription, 
        ServiceHostBase serviceHostBase)
    {
    }
}

The only thing I need to do here is to attach the instance provider (with the correct service type) to the dispatch runtime.  Finally, I just need to decorate my services with the SessionPerCallServiceBehavior attribute:

[SessionPerCallServiceBehavior]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class ComboService : IComboService
{
    private readonly IProductRepository _productRepository;
    private readonly ICategoryRepository _categoryRepository;

    public ComboService(IProductRepository productRepository, 
                        ICategoryRepository categoryRepository)
    {
        _productRepository = productRepository;
        _categoryRepository = categoryRepository;
    }

Notice we also configured our service to use the PerCall instance context mode.  We want this service to be instantiated for every single call to ensure that our ISession is not used across multiple client calls.  Configuring to the PerCall setting ensures that we only get one ISession per request.

Although we have our behavior up and running, we still need to find a place to configure StructureMap.

Configuring StructureMap

There’s just one more piece left to this puzzle.  I need to inject the StructureMap fluent configuration somewhere in this pipeline.  It only needs to happen once, so a custom service host factory would do the trick:

public class DIServiceHostFactory : ServiceHostFactory
{
    public DIServiceHostFactory()
    {
        StructureMapConfiguration
            .ScanAssemblies()
            .IncludeTheCallingAssembly()
            .With<DefaultConventionScanner>();
    }
}

The service host factory above isn’t coupled in any way to our custom service behavior, but we need to inject the StructureMap configuration so StructureMap knows where to look for our dependencies.  Finally, we need to configure our endpoint to use this service host factory, which is done in our case by editing the .svc file:

<%@ ServiceHost Language="C#" Debug="true" 
    Service="Wcf.ComboService"
    Factory="Wcf.DIServiceHostFactory" %>

With all of these pieces in place, our WCF endpoints can now follow the Session per Request pattern.

Wrapping it up

To configure our WCF application to use the Session per Request pattern, we needed to:

  • Create a wrapper around ISession for our repositories to depend on
  • Create an IInstanceProvider implementation that:
    • Creates an ISessionBuilder and stores it locally
    • Uses the With method on ObjectFactory to scope a specific instance of a dependency for a single call to GetObject
    • Closes the ISession when the service instance is released by WCF
  • Create the custom IServiceBehavior and Attribute that attaches the custom IInstanceProvider
  • Decorate our WCF service implementation with the custom IServiceBehavior and set the instance context mode to PerCall
  • Create a custom ServiceHostFactory to house our StructureMap configuration code
  • Modify our endpoint .svc file to use that custom ServiceHostFactory

With the Session per Request pattern in place, we can better control our transaction boundaries as we now have access to the underlying ISession instance used in each call.  Some additional WCF extension code allowed us to decorate each of our services that participates in the Session per Request pattern.  Although it can take quite a bit of code to configure WCF to follow these patterns, the good news is that we were able to do so, working with the framework.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in NHibernate, StructureMap, WCF. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://mbrownchicago.spaces.live.com Mike Brown

    Or you can just make your SessionBuilder return a static [ThreadLocal] ISession. Since each request runs in its own thread.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Mike

    We thought about that, but threading is also configurable in WCF, via the concurrency mode property. Our situation warranted a little more caution in that area, so we opted for the ObjectFactory/IInstanceProvider route.

    Thanks for the tip!

  • http://scottic.us Scott Bellware

    > I like this implementation of finding ISession rather than a service locator

    What you have is a service locator. You just happen to be passing the service provider to the client as a contructor argument.

  • http://paulbatum.blogspot.com Paul Batum

    Hi Jimmy! I really enjoyed this post, as I had to go through this process a few months ago and it was interesting to see the small differences in implementation.

    One thing I did differently was to avoid using lazy initialisation of the ISessionFactory. It was annoying to start up the wcf service and then have the first service request be really slow. It also seems to me that using lazy initialization as you are has another slight problem: when the application starts up for the first time, isn’t it possible for multiple threads to wind their way into ISessionBuilder.Initialize() and end up building the session factory multiple times? Or am I missing something?

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Scott

    Yep, you’re right. That should have read *static* service locator.

    @Paul

    This is something a double-check lock pattern would help with. We thought about a static constructor or putting it in the field initializer, but exceptions generated inside those can be a real pain to troubleshoot.

  • http://mbrownchicago.spaces.live.com Mike Brown

    Since you’re not using ThreadLocal mayb you could put your Initialize function in the static constructor. It gets called the first time the class is loaded, then you can get rid of the double lock check. Oh wait you already talked about that. Gosh you’re pretty bright ;)

  • http://paulbatum.blogspot.com Paul Batum

    Yeah a double check lock will definitely do the trick. The ye olde enterprise nhibernate sample on codeplex does it an interesting way using a nested type. But I agree that as soon as you do it on type initalization the exceptions are more of a pain to work with.

  • http://neilmosafi.blogspot.com Neil Mosafi

    Hi, can you explain why you need the ISessionBuilder in first place. Why can’t you make the ISession a direct dependency of the repository, and then get your container to pass a shared instance to all your repositories. So your constructor would simply be

    public ProductRepository(ISession session) { _session = session; }

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Paul, @Mike

    The other problem I’m running into is that I have a hard time testing anything multi-threaded with any consistency. Unless I can write a good test for it, I just have a tough time convincing myself it works.

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Neil

    I dunno, I’ve never really tried going through a container. Since it always has to be built from an ISessionFactory, it just made more sense to me to wrap it all up. Have you been able to get it in through the container?

  • http://realfiction.net Frank Quednau

    Hi there,
    I thought I add some more spice to this by pointing to my post today – (http://realfiction.net/?q=node/167)
    I thought we should have honorable mentions of NH’s possibility to define a class that provides a “Current Session” (which you get via sessionFactory.GetCurrentSession()) as well as making use of the WCF InstanceContext. Cheers!

  • http://neilmosafi.blogspot.com Neil Mosafi

    Hey Jimmy… referring back to my comment from last month – I spiked implementing this and I was completely dumb in thinking I could depend directly on the ISession interface in my repository! The reason is that repositories are usually configured as singletons – therefore even if the session is per-call you’re still gonna get the same instance for your repositories and everything will come crashing to a halt!

    Anyway I actually think Frank’s suggestion is best – defining a context for NHibernate’s GetCurrentSession() method and delegating that to an IExtension in WCF. That is what I am going to propose to the rest of my team anyway!

    Cheers
    Neil

  • http://jimmybogard.lostechies.com Jimmy Bogard

    @Neil

    Yep, the contextual session seems to be the way to go. Let me know how it goes!

  • http://www.lostechies.com/members/seanbiefeld/default.aspx Sean Biefeld

    Uber-useful! Mad props to you sir. Thanks much!

  • Pavan Kumar Puttaparthi Tiruma

    Thanks for this article. Is it possible for you to upload the solution as well?
    To tell truth I’m a newbie to StructureMap and I would like to use for a scenario where there are multiple Service projects with each project potentially having multiple service contract implementation (such as PingService, CustomerService, AssetService, CalculationService) and finally a Web application that has all the service files (i.e. multiple .svc files)
    I want to use StructureMap on WCF so that but have it all registered in one place (i.e. inside web application) and I don’t know how it works.
    Thanks for your help

    • Anonymous

      So unfortunately I wrote this post many years ago and the code is all lost. Sorry! You can try the StructureMap mailing list, however.