After Thought

Unit of Work Part 2

leave a comment »

In the previous post we started off with a brief discussion on Unit of Work and its implementation. We also implemented  ISessionContainer that is a wrapper for ISession and used it to persist changes into the database. In this post let us see if we can isolate the below piece of code that has to be repeated in all the methods that deals with repository.

try
{
	// do work
	_repository.Save(Entity);
	_sessionContainer.Commit();
}
finally
{
	_sessionContainer.Dispose();
}

Following implementation is inspired by Fubu Behaviors concept. Imagine every call from the client or web as a request and this request has to pass through a Request handler to reach our business logic. Let us create an interface IRequestHandler that would attempt to encapsulate a Request.

public interface IRequestHandler
{
  TOutput ProcessRequest<TInput1, TInput2, TOutput>(TInput1 input1, TInput2 input2, Func<TInput1, TInput2, TOutput> func)
    where TInput1 : class
    where TInput2 : class
    where TOutput : class;
}

The above interface takes in two input entities and a func that process these input entities and returns an output entity. Now let us go ahead and implement it.

public class AtomicRequestHandler : IRequestHandler
{
	private readonly ISessionContainer _sessionContainer;

	public AtomicRequestBehavior(ISessionContainer sessionContainer)
	{
		_sessionContainer = sessionContainer;
	}

	public TOutput ProcessRequest<TInput1, TInput2, TOutput>(TInput1 input1, TInput2 input2, Func<TInput1, TInput2, TOutput> func)
		where TInput1 : class
		where TInput2 : class
		where TOutput : class
	{
		try
		{
			var output = func.Invoke(input1, input2);

			_sessionContainer.Commit();

			return output;
		}
		finally
		{
			_sessionContainer.Dispose();
		}
	}
}

The name AtomicRequestHandler (name is subject to change upon a better name suggestion) means Handler for one request (imagine a web request). Initialized SessionContainer gets injected to AtomicRequestHandler.The ProcessRequest method invokes the method that has to be executed which in this case is UpdateBook. Upon completion of execution of UpdateBook method, it commits the transaction and closes the session. In case of any error anywhere in the execution, the transaction and session are closed throwing away all the unsaved changes.

Now let us re-implement the UpdateBook method with AtomicRequestHandler in mind.

public class SampleService : ISampleService
{
   private readonly IRepository _repository;

   public SampleService(IRepository repository)
   {
      _repository = repository;
   }

   public Book UpdateBook(Book book, Author author)
   {
      book.AddAuthor(author);
      book.Price =100m;
     _repository.Save(book);
     return book;
   }
}

The above illustration has no sign of SessionContainer at all. The reason we were able to separate the code so easily is because of Inversion of Control.

StructureMap is IoC of choice in my implementations, but you can choose to use your favorite IoC.  The following code shows how all this is magically constructed.

ISampleService sampleService = ObjectFactory.GetInstance<ISampleService>();
IRequestHandler atomicRequestHandler = ObjectFactory.GetInstance<IRequestHandler>();
Book result = atomicRequestHandler.ProcessRequest<Book, Author, Book>(GetBook(), GetAuthor(), sampleService.UpdateBook)

The above code calls atomicRequestHandler.ProcessRequest method with input entities – Book and Author and sampleService.UpdateBook method as a delegate that makes sure that the UpdateBook method is executed within the transaction boundary.

This is exactly how Fubu makes sure your web Request is executed within a transaction boundary. The Handle Request method in ActionHttpHandler redirects request to the action method through a behavior similar to AtomicRequestHandler.

You can implement this in ASP.net MVC by writing your own CustomHttpModule that initializes a new SessionContainer on BeginRequest and disposes it on EndRequest. You can alternatively do this in Application_BeginRequest and Application_EndRequest in Global.asax.cs file. ActionFilter is another place where you can stick in unit of work, but it is generally not recommended as you will have to do this for every single action.

If you compare them, Fubu does it the best when compared to ASP.Net Mvc, because of its architectural preference of Composition over Inheritance.

Finally, I wouldn’t have been able to write this exhaustive analysis on Unit of Work if not for multiple discussions with Chad Myers, Josh Flanagan and Weston Binford. Download the sample application on which the examples discussed above are based on.

Advertisements

Written by shashankshetty

October 29, 2009 at 10:33 pm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: