简体   繁体   中英

How to implement Session Per Conversation pattern with WebAPI/ NHibernate

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM