0

I have an MVC project that I exclusively employ a custom "Unit Of Work" pattern that uses NHibernate on the back end, which I expose to my application as IUnitOfWork and IUnitOfWorkFactory interfaces; These interfaces are injected as my NHibernate implementations via Ninject.

I use my UOW in a modified "session per request" style... I explicitly generate my IUnitOfWork from my injected IUnitOfWorkFactory when I need to perform database operations; it seems much easier to keep the CRUD where it belongs (out of my views and controllers) and effectively prevents accidental N+1 coding issues. Of course, it's a little harder to implement, but to date, I've been pretty happy with it.

Now I want to implement a WebAPI presenting IQueryable<Entity>-style REST calls, and my UOW pattern isn't digging it. The Queryables invariably blow up, attempting to invoke a disposed NHibernate session.

I've read some stuff online about how to implement a DelegatingHandler to manage the session for a WebAPI call... but I see several problems:

  1. It seems that all the examples are assuming a "Session per Request" pattern... which is by far the most popular pattern, but not exactly one which I am using, so I'm not sure that is even the proper direction to go.
  2. It's not clear how I can implement this handler exclusively for these Web API calls.
  3. I've seen a lot of suggestions to use a "Session per Conversation" pattern which is potentially even longer-lived than the "Session per Request" pattern... it sounds like it might be appropriate for this endeavor, but the documentation on how to implement it is a little sparse.
  4. All the sample implementations I've seen pretty much tightly couple the NHibernate ISession to the web application, using a built-in NHibernate mechanism (CurrentSessionContext.Bind(ISession)); I'd much rather reference my IUnitOfWork interface, and trust it to maintain the session it needs to.

So my question is, how can I implement a IQueryable<Entity> RESTful API using my own IUnitOfWork interface going against loosely-coupled NHibernate back-end?

3
  • Have you seen this question/answer, UOW example using WebApi? stackoverflow.com/questions/15070253/… Commented Feb 24, 2014 at 6:48
  • It's interesting, but I don't think I can glean what I need out of it. Commented Feb 24, 2014 at 13:38
  • Embrace rather than abstract seems to be the way people are going at the moment. Commented Feb 25, 2014 at 8:28

1 Answer 1

1

You would face the same problem with a straightforward session-per-request implementation. For example:

// GET api/companies
public IQueryable<Company> GetCompanies()
{
    return _session.Query<Company>();
}

I usually wrap all database operations, including selects, in a transaction but because query execution is deferred I can't do it in this method. It is possible to do so by creating an ActionFilter and overriding OnActionExecuted but the difficulty is gaining a reference to the ISession or your IUnitOfWork implementation in the filter. There are examples of how to accomplish this using Ninject and other dependency injection frameworks on the web.

Personally I don't see the value of abstracting the ISession, especially in Web API where it would be very rare to have a resource that did not perform a database operation. Session-per-conversation is definitely not a good pattern for this; it generally refers to keeping a session open over multiple server round trips.

My preferred architecture is to use Ninject to manage ISessionFactory and ISession lifetime (singleton and per-request, respectively) and to inject the ISession into the Api controllers. But you could also inject it into a repository or unit of work implementation.

Sign up to request clarification or add additional context in comments.

4 Comments

Well the primary reason I want to abstract the ISession is because it smells like a tight coupling where everything else in my application is handled through clean interfaces. To date, my application has no reference to NHibernate at all... I'd like to keep it that way.
I think my answer is still relevant, you can use an ActionFilter as described.
There is another answer, move your web API to another end point (another url in effect) in its own project and embrace NH rather than abstract. With abstracting you will lose the the ability to lazy load and return an IQueryable for later use. This is one of those "I won't like the answer questions..." You really don;t have many options.
@Rippo yeah I don't like that answer... but it may be the practical thing to do.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.