Code Elegance

Windsor Container and NHibernate sessions

When developing MVVM WPF applications that use NHibernate as ORM one of the problems that you encounter is how to manage the sessions and keep the application fully testable.

I like using a Session per “screen” that in the MVVM world is equivalent to use “one Session per ViewModel”.

I also like to separate the presentation logic from the rest so I also create a Model for each ViewModel (even if this is not strictly necessary)

Finally the Model use one or more repository to access the database.

So, the NHibernate session is tied to the life of the Model and all the repositories that belongs the same model should share the same session so I can build transaction between repositories.

In addition to this I would like to inject the interfaces of the dependencies: the ViewModel will get the IModel, and the Model will get the IRepository1, IRepository2.

This picture should clarify the complete schema:

NHSessions

To create this scenario I choose Castle Windsor as a container and with the help of German Shuager, I defined this particular registration method:

public static void RegisterSharedWithFactory<TService>(Function<TService> factory)
{
  _kernel.AddFacility<FactorySupportFacility>()
    .Register(Component.For<TService>()
      .UsingFactoryMethod(factory)
      .LifeStyle.Custom<ResolutionContextLifestyleManager>());
}

This method registers a component using a Factory method to create the instance since we cannot create an instance of the ISession but we must use a SessionFactory. Then sets the the lifestyle to a custom ResolutionContextLifestyleManager to be sure that  in the same context the dependencies are created only once.

The implementation of ResolutionContextLifestyleManager is written by German and can be found here.

To understand what it does, consider this test:

[Fact]
public void Two_Repo_In_The_Same_Model_Should_Have_Same_Session()
{
  Container.Initialize();
  Container.RegisterSharedWithFactory<ISession>(() => SessionHelper.OpenSession());
  Container.Register<IRepo1, Repo1>();
  Container.Register<IRepo2, Repo2>();
  Container.Register<IModel1, Model1>();

  IModel1 model1 = Container.Resolve<IModel1>();

  Assert.Equal(model1.Repo1.Session, model1.Repo2.Session); // Repo1 and Repo2 shares the same session
}

The model uses two repositories that uses the same instance of ISession exactly like in the picture above.

This configuration is very useful to manage the session in the right manner with NHibernate and Castle Windsor container and assure us the testability of all the components.

No comments

How to mock the IMessageBroker

On the blogs there are a lot of articles about the M-V-VM pattern showing how to decouple the various components of our application to make it modular.

One of the component that helps the ViewModels to communicate with other ViewModels is the MessageBroker (AKA EventAggregator, AKA Mediator): a manager class that route the messages from the ViewModels.

One good implementation of the Mediator for the MVVM is this http://sachabarber.net/?p=477:

To make it more testable we extract an interface:

public interface IMessageBroker
{
  void NotifyColleagues(MessageType messageType);
  void Register<T>(Action<T> action, MessageType messageType);
}

 

If you TDD your application or if you write unit test you could need to mock the IMessageBroker and it’s not immediate because the Action<T>.

Alessandro wrote a solution that is interesting using Moq:

[Fact]
public void Sample_Test()
{
  Mock<IMessageBroker> broker = new Mock<IMessageBroker>();
  Action<String> action = null;

  broker
    .Setup(b => b.Subscribe(It.IsAny<Action<String>>()))
    .Callback<Action<String>>(a => action = a);

  new FakeViewModel(broker.Object);

  action.Invoke("TestMessage");

  // Asserts...
}

Moq is a powerful mock framework and it’s simplicity make the elegant and easy to read!

 

No comments