Note that there are some explanatory texts on larger screens.

plurals
  1. POImplementing UnitOfWork with Castle.Windsor
    text
    copied!<p>Simple question.</p> <blockquote> <p><strong>How do I use UnitOfWork with Castle.Windsor, nHibernate, and ASP.NET MVC?</strong></p> </blockquote> <p>Now for the extended details. In my quest to understand the <code>UnitOfWork</code> pattern, I'm having difficulty coming across anything that uses a direct example in conjunction with <code>Castle.Windsor</code>, specifically in regards to the way it needs to be installed. </p> <p>Here is my understanding so far.</p> <h2>IUnitOfWork</h2> <ul> <li>The <code>IUnitOfWork</code> interface is used to declare the pattern</li> <li>The <code>UnitOfWork</code> class must <code>Commit</code> and <code>Rollback</code> transactions, and Expose a <code>Session</code>.</li> </ul> <p>So with that said, here is my <code>IUnitOfWork</code>. (I am using <code>Fluent nHibernate</code>)</p> <pre><code>public interface IUnitOfWork : IDisposable { ISession Session { get; private set; } void Rollback(); void Commit(); } </code></pre> <p>So here is my <code>Castle.Windsor</code> Container Bootstrapper (ASP.NET MVC)</p> <pre><code>public class WindsorContainerFactory { private static Castle.Windsor.IWindsorContainer container; private static readonly object SyncObject = new object(); public static Castle.Windsor.IWindsorContainer Current() { if (container == null) { lock (SyncObject) { if (container == null) { container = new Castle.Windsor.WindsorContainer(); container.Install(new Installers.SessionInstaller()); container.Install(new Installers.RepositoryInstaller()); container.Install(new Installers.ProviderInstaller()); container.Install(new Installers.ControllerInstaller()); } } } return container; } } </code></pre> <p>So now, in my <code>Global.asax</code> file, I have the following...</p> <pre><code> protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); // Register the Windsor Container ControllerBuilder.Current .SetControllerFactory(new Containers.WindsorControllerFactory()); } </code></pre> <h2>Repository</h2> <p>Now I understand that I need to pass the <code>ISession</code> to my Repository. So then, let me assume <code>IMembershipRepository</code>.</p> <pre><code>class MembershipRepository : IMembershipRepository { private readonly ISession session; public MembershipRepository(ISession session) { this.session = session; } public Member RetrieveMember(string email) { return session.Query&lt;Member&gt;().SingleOrDefault( i =&gt; i.Email == email ); } } </code></pre> <p>So I am confused, now. Using this method, the <code>ISession</code> doesn't get destroyed properly, and the <code>UnitOfWork</code> never gets used. </p> <p>I've been informed that <code>UnitOfWork</code> needs to go in the Web Request Level - but I cannot find anything explaining how to actually go about this. I do not use a <code>ServiceLocator</code> of any sort ( as when I tried, I was told this was also bad practice... ).</p> <blockquote> <blockquote> <p>Confusion -- How does a <code>UnitOfWork</code> get created?</p> </blockquote> <p>I just don't understand this, in general. My thought was that I would start passing <code>UnitOfWork</code> into the <code>Repository</code> constructors - but if it has to go in the Web Request, I'm not understanding where the two relate.</p> </blockquote> <h2>Further Code</h2> <p>This is extra code for clarification, simply because I seem to have a habit of never providing the right information for my questions.</p> <h2>Installers</h2> <pre><code>public class ControllerInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register( AllTypes.FromThisAssembly() .BasedOn&lt;IController&gt;() .Configure(c =&gt; c.LifeStyle.Transient)); } } public class ProviderInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register( Component .For&lt;Membership.IFormsAuthenticationProvider&gt;() .ImplementedBy&lt;Membership.FormsAuthenticationProvider&gt;() .LifeStyle.Singleton ); } } public class RepositoryInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register( Component .For&lt;Membership.IMembershipRepository&gt;() .ImplementedBy&lt;Membership.MembershipRepository&gt;() .LifeStyle.Transient ); container.Register( Component .For&lt;Characters.ICharacterRepository&gt;() .ImplementedBy&lt;Characters.CharacterRepository&gt;() .LifeStyle.Transient ); } } public class SessionInstaller : Castle.MicroKernel.Registration.IWindsorInstaller { private static ISessionFactory factory; private static readonly object SyncObject = new object(); public void Install(Castle.Windsor.IWindsorContainer container, IConfigurationStore store) { container.Register( Component.For&lt;ISessionFactory&gt;() .UsingFactoryMethod(SessionFactoryFactory) .LifeStyle.Singleton ); container.Register( Component.For&lt;ISession&gt;() .UsingFactoryMethod(c =&gt; SessionFactoryFactory().OpenSession()) .LifeStyle.Transient ); } private static ISessionFactory SessionFactoryFactory() { if (factory == null) lock (SyncObject) if (factory == null) factory = Persistence.SessionFactory.Map(System.Web.Configuration.WebConfigurationManager.ConnectionStrings["Remote"].ConnectionString); return factory; } } </code></pre> <h2>UnitOfWork</h2> <p>Here is my <code>UnitOfWork</code> class verbatim.</p> <pre><code>public class UnitOfWork : IUnitOfWork { private readonly ISessionFactory sessionFactory; private readonly ITransaction transaction; public UnitOfWork(ISessionFactory sessionFactory) { this.sessionFactory = sessionFactory; Session = this.sessionFactory.OpenSession(); transaction = Session.BeginTransaction(); } public ISession Session { get; private set; } public void Dispose() { Session.Close(); Session = null; } public void Rollback() { if (transaction.IsActive) transaction.Rollback(); } public void Commit() { if (transaction.IsActive) transaction.Commit(); } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload