Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement NHibernate session per request without a dependency on NHibernate?

I've raised this question before but am still struggling to find an example that I can get my head around (please don't just tell me to look at the S#arp Architecture project without at least some directions).

So far I have achieved near persistance ignorance in my web project. My repository classes (in my data project) take an ISession in the constructor:

public class ProductRepository : IProductRepository
{
    private ISession _session;
    public ProductRepository(ISession session) {
        _session = session;
    }

In my global.asax I expose the current session and am creating and disposing session on beginrequest and endrequest (this is where I have the dependency on NHibernate):

    public static ISessionFactory SessionFactory = CreateSessionFactory();

    private static ISessionFactory CreateSessionFactory() {
        return new Configuration() 
            .Configure()
            .BuildSessionFactory();
    }

    protected MvcApplication()  {
        BeginRequest += delegate {
            CurrentSessionContext.Bind(SessionFactory.OpenSession());
        };
        EndRequest += delegate {
            CurrentSessionContext.Unbind(SessionFactory).Dispose();
        };
    }

And finally my StructureMap registry:

    public AppRegistry() {
        For<ISession>().TheDefault
            .Is.ConstructedBy(x => MvcApplication.SessionFactory.GetCurrentSession());

        For<IProductRepository>().Use<ProductRepository>();
    }

It would seem I need my own generic implementations of ISession and ISessionFactory that I can use in my web project and inject into my repositories?

So just to clarify - I am using NHibernate in my repository layer and want to use a session-per-(http)request. Therefore I am injecting an ISession into my repository constructors (using structuremap). Currently to create and dispose the sessions in each request I have had to reference NHibernate from my web project. This is the dependency I would like to remove.

Thanks, Ben

like image 265
Ben Foster Avatar asked May 26 '10 12:05

Ben Foster


2 Answers

Why don't you create an IHttpModule and perform your creation and disposing there (probably in the Begin_Request and End_Request events), but put your IHttpModule inside the project that has your NHibernate dependency. eg.

namespace MyWebApp.Repository.NHibernateImpl
{
    public class NHibernateModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(Context_BeginRequest);
            context.EndRequest += new EventHandler(Context_EndRequest);
        }

        private void Context_BeginRequest(object sender, EventArgs e)
        {
            // Create your ISession
        }

        private void Context_EndRequest(object sender, EventArgs e)
        {
            // Close/Dispose your ISession
        }

        public void Dispose()
        {
            // Perhaps dispose of your ISessionFactory here
        }
    }
}

There is maybe a better way, I'm interested to know this as well, so any alternative suggestions?

like image 140
Sunday Ironfoot Avatar answered Sep 28 '22 21:09

Sunday Ironfoot


In my opinion, you should embrace the ISession and work with it directly. The problem with many session-per-request implementations is that they delay committing database changes until the end of the HTTP request. If the transaction fails, all you can do at that point is direct the user to a generic error page. It's much better to manage the transaction on the page so that you can catch and handle errors more effectively. If you take this route then you need to access the ISession or a wrapper to control the transaction.

Also, at some point your application will probably need to use properties or methods exposed by ISession, especially Merge and Load.

like image 44
Jamie Ide Avatar answered Sep 28 '22 23:09

Jamie Ide