How I use NHibernate with fubuMVC

I’m currently upgrading my production website to use the excellent fubuMVC framework and have been writing about my experiences with it.

One of the early needs for me was to integrate NHibernate and I wanted to do this in as simple a way as possible without extra unit of work classes or transaction/session managers.
Here’s what I came up with:

Every request, I want a new session for the entire request and I want everything within that request in a transaction that can be committed or rolled back. However not all requests will use a session, so it will be inefficient to open a new session on every single request, so I need to make that session lazy.
Let’s start with the specifications:

    [Subject(typeof(SimpleUnitOfWorkBehaviour))]
    public class when_invoked
    {
        Establish context = () =>
        {
            _sessionFactory = new Mock<ISessionFactory>();
            _fubuRequest = new Mock<IFubuRequest>();
            _innerBehaviour = new Mock<IActionBehavior>();

            _simpleUnitOfWorkBehaviour = new SimpleUnitOfWorkBehaviour(_sessionFactory.Object, 
_fubuRequest.Object) { InnerBehavior = _innerBehaviour.Object }; }; Because of = () => _simpleUnitOfWorkBehaviour.Invoke(); It should_provide_a_lazy_session_in_the_fubu_request = () => _fubuRequest.Verify(f => f.Set(Moq.It.IsAny<Lazy<ISession>>())); It should_invoke_the_inner_behaviour = () => _innerBehaviour.Verify(b => b.Invoke()); It should_not_yet_open_the_session = () => _sessionFactory.VerifyNeverHappened(f => f.OpenSession()); static SimpleUnitOfWorkBehaviour _simpleUnitOfWorkBehaviour; static Mock<ISessionFactory> _sessionFactory; static Mock<IFubuRequest> _fubuRequest; static Mock<IActionBehavior> _innerBehaviour; }

I’m specifying a new fubuMVC behaviour – SimpleUnitOfWorkBehaviour – which is injected with an NHibernate session factory and the FubuRequest via the constructor and the InnerBehaviour via a property as per the fubuMVC inner behaviour convention.
Once invoked, this behaviour should provide a lazy session in the fubu request, it should invoke the inner behaviour but, importantly it should not yet open the session.
Here’s the implementation of that:

    public class SimpleUnitOfWorkBehaviour : IActionBehavior
    {
        readonly IFubuRequest _fubuRequest;
        readonly ISessionFactory _sessionFactory;

        public IActionBehavior InnerBehavior { get; set; }

        public SimpleUnitOfWorkBehaviour(ISessionFactory sessionFactory, 
IFubuRequest fubuRequest) { _sessionFactory = sessionFactory; _fubuRequest = fubuRequest; } public void Invoke() { _fubuRequest.Set(new Lazy<ISession>()); InnerBehavior.Invoke(); } public void InvokePartial() { InnerBehavior.InvokePartial(); } }

Pretty basic (there isn’t even an actual session yet) but functional so it needs pushing with some new specifications:

    [Subject(typeof(SimpleUnitOfWorkBehaviour))]
    public class when_invoked_and_the_inner_behaviour_chain_consumes_the_session
    {
        Establish context = () =>
        {
            _transaction = new Mock<ITransaction>();
            _session = new Mock<ISession>();
            _session.Setup(s => s.BeginTransaction()).Returns(_transaction.Object);
            _session.SetupGet(s => s.Transaction).Returns(_transaction.Object);

            _sessionFactory = new Mock<ISessionFactory>();
            _sessionFactory.Setup(f => f.OpenSession()).Returns(_session.Object);

            _fubuRequest = new Mock<IFubuRequest>();
            _fubuRequest.Setup(f => f.Set(Moq.It.IsAny<Lazy<ISession>>()))
                        .Callback<Lazy<ISession>>(lazySession => _lazySession = lazySession);

            _innerBehaviour = new Mock<IActionBehavior>();
            _innerBehaviour.Setup(b => b.Invoke()).Callback(() => {var s=_lazySession.Value;});

            _simpleUnitOfWorkBehaviour = new SimpleUnitOfWorkBehaviour(_sessionFactory.Object, 
_fubuRequest.Object) { InnerBehavior = _innerBehaviour.Object }; }; Because of = () => _simpleUnitOfWorkBehaviour.Invoke(); It should_open_the_session = () => _sessionFactory.Verify(f => f.OpenSession()); It should_begin_a_transaction = () => _session.Verify(s => s.BeginTransaction()); It should_commit_the_transaction = () => _transaction.Verify(t => t.Commit()); It should_dispose_the_session = () => _session.Verify(s => s.Dispose()); static SimpleUnitOfWorkBehaviour _simpleUnitOfWorkBehaviour; static Mock<ISessionFactory> _sessionFactory; static Mock<IFubuRequest> _fubuRequest; static Mock<IActionBehavior> _innerBehaviour; static Lazy<ISession> _lazySession; static Mock<ISession> _session; static Mock<ITransaction> _transaction; }

This one is a bit more complex as it is setting up quite a few behaviours on the mocks – first it sets up the session and transaction along with the session factory providing that session when OpenSession is called.
Then there is a callback on the FubuRequest so that when the Lazy<ISession> is set, it can be captured and finally the inner behaviour is set up to consume the captured lazy session.

It should then open the session, begin a transaction, commit it and then dispose of that session.
Here’s the implementation so far:

    public class SimpleUnitOfWorkBehaviour : IActionBehavior
    {
        readonly IFubuRequest _fubuRequest;
        readonly ISessionFactory _sessionFactory;
        ISession _session;

        public IActionBehavior InnerBehavior { get; set; }

        public SimpleUnitOfWorkBehaviour(ISessionFactory sessionFactory, 
IFubuRequest fubuRequest) { _sessionFactory = sessionFactory; _fubuRequest = fubuRequest; } public void Invoke() { _fubuRequest.Set(new Lazy<ISession>(() =>
_session ?? (_session = CreateTransactionalSession()))); InnerBehavior.Invoke(); if (_session != null) { _session.Transaction.Commit(); _session.Dispose(); } } ISession CreateTransactionalSession() { var session = _sessionFactory.OpenSession(); session.BeginTransaction(); return session; } public void InvokePartial() { InnerBehavior.InvokePartial(); } }

There is no error handling yet, so it is time for a specification for that:

    [Subject(typeof(SimpleUnitOfWorkBehaviour))]
    public class when_invoked_and_the_inner_behaviour_chain_consumes_the_session_but_
something_goes_wrong { Establish context = () => { _transaction = new Mock<ITransaction>(); _session = new Mock<ISession>(); _session.Setup(s => s.BeginTransaction()).Returns(_transaction.Object); _session.SetupGet(s => s.Transaction).Returns(_transaction.Object); _sessionFactory = new Mock<ISessionFactory>(); _sessionFactory.Setup(f => f.OpenSession()).Returns(_session.Object); _fubuRequest = new Mock<IFubuRequest>(); _fubuRequest.Setup(f => f.Set(Moq.It.IsAny<Lazy<ISession>>())) .Callback<Lazy<ISession>>(lazySession => _lazySession = lazySession); _exception = new Exception(); _innerBehaviour = new Mock<IActionBehavior>(); _innerBehaviour.Setup(b => b.Invoke()).Callback(() => { var s = _lazySession.Value; throw _exception; }); _simpleUnitOfWorkBehaviour = new SimpleUnitOfWorkBehaviour(_sessionFactory.Object,
_fubuRequest.Object) { InnerBehavior = _innerBehaviour.Object }; }; Because of = () =>
_caughtException = Catch.Exception(() => _simpleUnitOfWorkBehaviour.Invoke()); It should_rollback_the_transaction = () => _transaction.Verify(t => t.Rollback()); It should_dispose_the_session = () => _session.Verify(s => s.Dispose()); It should_not_swallow_the_problem = () => _caughtException.ShouldEqual(_exception); static SimpleUnitOfWorkBehaviour _simpleUnitOfWorkBehaviour; static Mock<ISessionFactory> _sessionFactory; static Mock<IFubuRequest> _fubuRequest; static Mock<IActionBehavior> _innerBehaviour; static Lazy<ISession> _lazySession; static Mock<ISession> _session; static Mock<ITransaction> _transaction; static Exception _exception; static Exception _caughtException; }

This specification has the same kind of setup yet this time the inner behaviour has changed to not only consume the session, but to throw an exception. It should then rollback the transaction, dispose the session and not swallow the exception and let it bubble up.

Here’s the final implementation of the SimpleUnitOfWorkBehaviour:

    public class SimpleUnitOfWorkBehaviour : IActionBehavior
    {
        readonly IFubuRequest _fubuRequest;
        readonly ISessionFactory _sessionFactory;
        ISession _session;

        public IActionBehavior InnerBehavior { get; set; }

        public SimpleUnitOfWorkBehaviour(ISessionFactory sessionFactory, 
IFubuRequest fubuRequest) { _sessionFactory = sessionFactory; _fubuRequest = fubuRequest; } public void Invoke() { _fubuRequest.Set(new Lazy<ISession>(() =>
_session ?? (_session = CreateTransactionalSession()))); try { InnerBehavior.Invoke(); if (_session != null) _session.Transaction.Commit(); } catch (Exception) { if (_session != null) _session.Transaction.Rollback(); throw; } finally { if (_session != null) _session.Dispose(); } } ISession CreateTransactionalSession() { var session = _sessionFactory.OpenSession(); session.BeginTransaction(); return session; } public void InvokePartial() { InnerBehavior.InvokePartial(); } }

Finally, I need to think about how this lazy session will be consumed – I want a delegate to the session rather than anything else knowing about the laziness of the session, so I’m going to use a http scoped Func<ISession> that is injected into any instance that needs a session.

So I need to set up the container accordingly:

 
    public class ContainerConfigurer : IConfigureContainers
    {
        public ContainerConfigurer()
        {
            Configuration = x =>
            {
                x.Scan(i =>
                {
                    i.TheCallingAssembly();
                    i.AssemblyContainingType<UserVerifier>();
                    i.SingleImplementationsOfInterface();
                });

                x.For<Func<ISession>>().HttpContextScoped().Use(
c => () => c.GetInstance<IFubuRequest>().Get<Lazy<ISession>>().Value);
x.For<ISessionFactory>().Singleton().Use(
c => c.GetInstance<ISessionFactoryCreator>().CreateFactory("Xerces"));
x.For<ISessionFactoryCreator>().Singleton().Use<SessionFactoryCreator>(); }; } }

I’m registering a delegate for an ISession that when invoked will get the current IFubuRequest and obtain the current Lazy<ISession> value, thus opening the session and providing it on demand for that current request.

So there it is a simple unit of work behaviour for fubuMVC that defers the opening of the session until needed.

(Note that this does not work if I have a singleton instance that consumes the Func<ISession> as the resolution inside the delegate will be in the wrong nested scope. However I personally always ensure that singleton state is kept outside of data providers that need the session - the data providers themselves are transient and can be injected with singleton caches for example).

Here’s a simple example of that delegate in use:

    public class UserObtainer : IObtainUsers
    {
        readonly Func<ISession> _sessionProvider;

        public UserObtainer(Func<ISession> sessionProvider)
        {
            _sessionProvider = sessionProvider;
        }

        public User ObtainUserFromEmailAddress(string emailAddress)
        {
            var session = _sessionProvider();

            return session.CreateCriteria<User>()
                .Add<User>(u => u.EmailAddress == emailAddress)
                .UniqueResult<User>();
        }
    }



0 comments: