Using NHibernate In Your Service Layer
Posted by Davy Brion on 11th December 2009
I have an old post where i discuss how you can manage your NHibernate sessions in a service layer scenario. Now, the example of the service layer code in that post was pretty poor and people were asking for a better example. Hopefully, this post will do a better job at making sure everything is clear
First of all, the idea is to make sure that managing the NHibernate session (creating it, starting a transaction, committing or rolling back the transaction and closing the session) is taken care of automatically so you no longer have to worry about it. I also want to avoid passing the NHibernate session around all the time. This means that it will be created automatically when a request is sent to your service layer and stored in some place that will keep the instance alive during the handling of the service layer request. Every class that needs a reference to the current session (ideally only classes that deal purely with data access) will be able to retrieve it very easily, all in a thread-safe manner that can never be influenced by other concurrent requests.
First of all, you need something to wrap NHibernate’s ISessionFactory. I use the ISessionProvider for that:
public interface ISessionProvider
{
ISession Create();
}
public class SessionProvider : ISessionProvider
{
private readonly ISessionFactory sessionFactory;
public SessionProvider(string mappingAssemblyName)
{
Configuration configuration = new Configuration()
.Configure()
.AddAssembly(mappingAssemblyName);
sessionFactory = configuration.BuildSessionFactory();
}
public ISession Create()
{
return sessionFactory.OpenSession();
}
}
In my case, i configure the IOC container to pass the name of the assembly that contains the mappings to the constructor of the SessionProvider class. If you’re using this code directly in your application, you could just as well hardcode the name of the assembly here.
You’ll also need something that allows you to store and retrieve the NHibernate session for the duration of the current request. I use the IActiveSessionManager for that:
public interface IActiveSessionManager
{
ISession GetActiveSession();
void SetActiveSession(ISession session);
void ClearActiveSession();
bool HasActiveSession { get; }
}
public class ActiveSessionManager : IActiveSessionManager
{
private const string sessionKey = "_currentSession";
private readonly IRequestState requestState;
public ActiveSessionManager(IRequestState requestState)
{
this.requestState = requestState;
}
public ISession GetActiveSession()
{
if (Current == null)
{
throw new InvalidOperationException("There is no active ISession instance for this thread");
}
return Current;
}
public void SetActiveSession(ISession session)
{
if (Current != null)
{
throw new InvalidOperationException("There is already an active ISession instance for this thread");
}
Current = session;
}
public void ClearActiveSession()
{
Current = null;
}
public bool HasActiveSession
{
get { return Current != null; }
}
protected virtual ISession Current
{
get
{
return requestState.Get<ISession>(sessionKey);
}
set
{
requestState.Store(sessionKey, value);
}
}
}
This class will store the ISession instance in the current request state (definitely click on that link if you don’t know IRequestState yet).
Now we can create our own Unit Of Work. This is not a pure Unit Of Work because it doesn’t do any change tracking or anything like that, but it does take care of creating an NHibernate session (which does do change tracking and anything that a real Unit Of Work should do) and cleaning it up when the Unit Of Work is completed. Here’s my implementation:
public interface IUnitOfWork : IDisposable
{
void Clear();
void Flush();
ITransaction CreateTransaction();
ITransaction CreateTransaction(IsolationLevel isolationLevel);
}
public class UnitOfWork : Disposable, IUnitOfWork
{
private readonly IActiveSessionManager sessionManager;
private readonly ISession session;
private readonly bool isRootUnitOfWork;
public UnitOfWork(ISessionProvider sessionProvider, IActiveSessionManager sessionManager)
{
this.sessionManager = sessionManager;
if (sessionManager.HasActiveSession)
{
isRootUnitOfWork = false;
session = sessionManager.GetActiveSession();
}
else
{
isRootUnitOfWork = true;
session = sessionProvider.Create();
sessionManager.SetActiveSession(session);
}
}
public void Clear()
{
session.Clear();
}
public void Flush()
{
session.Flush();
}
public ITransaction CreateTransaction()
{
return CreateTransaction(IsolationLevel.ReadCommitted);
}
public ITransaction CreateTransaction(IsolationLevel isolationLevel)
{
if (session.Transaction != null && session.Transaction.IsActive)
{
throw new InvalidOperationException("nested transactions are not supported!");
}
return session.BeginTransaction(isolationLevel);
}
protected override void DisposeManagedResources()
{
if (isRootUnitOfWork)
{
if (session != null)
{
session.Close();
session.Dispose();
}
sessionManager.ClearActiveSession();
}
}
}
The idea is very simple. When the Unit Of Work is created, it asks the IActiveSessionManager if there is already an active session available. If not, it will create a new session through the ISessionProvider, and store it as the active session through the IActiveSessionManager. In the old implementation, the Unit Of Work would automatically create a new session in the constructor, but this obviously causes problems if you want to reuse a certain request handler from another request handler if they both depend on a IUnitOfWork instance. The IUnitOfWork interface doesn’t expose a lot of functionality but it’s all you need to manage your session in your service layer. It gives you the ability to create a transaction, clear the session and flush the session. When the IUnitOfWork is disposed, it will clean up the session and instruct the IActiveSessionManager to get rid of the session for this request.
Once you have this, you have all you need to prepare your service layer to take care of NHibernate session management automatically. I’m going to base the following service layer code example on Agatha (just because i think it’s the easiest way to implement a service layer
) but you can do exactly the same in your service layer. The important part is that you should configure your IOC container to inject a new instance of IUnitOfWork into the class that handles your service request. When the container injects the new instance, the NHibernate session will be created and stored in the IActiveSessionManager so there’s no more reason why you would have to do this yourself.
Now, i use the following class as the base class for all my request handlers that need NHibernate support:
public abstract class NhRequestHandler<TRequest, TResponse> : RequestHandler<TRequest, TResponse>
where TRequest : Request
where TResponse : Response
{
public IUnitOfWork UnitOfWork { get; set; }
protected override void DisposeManagedResources()
{
if (UnitOfWork != null) UnitOfWork.Dispose();
}
public override Response Handle(Request request)
{
using (ITransaction transaction = UnitOfWork.CreateTransaction())
{
Response response;
try
{
response = base.Handle(request);
transaction.Commit();
}
catch (Exception handlerException)
{
transaction.Rollback();
throw;
}
return response;
}
}
}
(Note: the real implementation contains a bit more logging but other than that this is the real thing)
If you don’t understand the whole request handling concept, please check out the first 3 posts in this series. Regardless of whether you’re using Agatha, your own Request/Response Service Layer or a classic (dare i say old-school?) service layer, the idea should be the same. Make sure this code is centralized in one place so you don’t have to repeat yourself all over your service layer code. Btw, in this case the IUnitOfWork instance is injected by the IOC container through Setter Injection instead of Constructor Injection. I’ve already discussed the reasons on why i prefer Setter Injection in this case here.
Now, you’re going to have some classes that will need to use an ISession instance to perform their tasks. I always create Repository classes for that, but the following approach would be similar for any other type of class which needs an ISession. Call them Data Access Objects, Data Access Classes or Sloppy Joes for all i care. Whatever you call these classes, they need a dependency on the IActiveSessionManager. Simply declare the IActiveSessionManager to be a dependency of your Sloppy Joe, i mean, Repository or DAO or whatever, like this:
public class Repository<T> : IRepository<T>
{
private readonly IActiveSessionManager activeSessionManager;
public Repository(IActiveSessionManager activeSessionManager)
{
this.activeSessionManager = activeSessionManager;
}
protected ISession Session
{
get { return activeSessionManager.GetActiveSession(); }
}
Now you can write request handlers like this:
public class GetCustomersRequestHandler : NhRequestHandler<GetCustomersRequest, GetCustomersResponse>
{
private readonly IRepository<Customer> repository;
public GetCustomersRequestHandler(IRepository<Customer> repository)
{
this.repository = repository;
}
public override Response Handle(GetCustomersRequest request)
{
var response = CreateTypedResponse();
response.Customers = ConvertToDtos(repository.FindAll(request.Criteria));
return response;
}
private CustomerDto[] ConvertToDtos(IEnumerable<Customer> customers)
{
// …
}
}
Obviously, this is a simple example but it works just as well for complex request handlers. Your NHibernate session is created and cleaned up automatically, without you having to write that code every single time. Each request handler will run in a transaction, and it will be committed or rolled back automatically without you having to do anything for it. And you only need to access the ISession instance in your Sloppy Joes.
Also keep in mind that you can also use the the ISessionProvider, IActiveSessionManager and IUnitOfWork in a purely web-based scenario as well if you want to.
Posted in NHibernate | 15 Comments »

