Ryan LanciauxNew Media Mercenary

RhinoCommons, NHibernate and ASP.NET MVC Part 4 - The MVC Application

May 26, 2008 by ryan

Finally we're to the point where we can see all our hard work come together. We have most of the hard work done but we still have a lot of ground to cover. If you haven't been following along, please check out Setting Up The Assemblies, Configuring the Application and Developing the Model.

Unit of Work

In some of my initial tests with NHibernate and ASP.NET MVC Pattern I kept seeing the benefits of having a Unit of Work or Session Per Request (that is opening and closing the NHibernate session at the begining and end of the http request respectively). To Recap a little, I started to write my own Session Per Request, however, Chad Myers pointed me to the Rhino Commons project which already implemented this. I think it's worthwhile becuase I don't really like putting NHibernate session code in my controller plus as Martin Fowler writes

A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work.

Luckily, with RhinoCommons, it's pretty easy to implement this pattern (check out Ayende's post on this). In a standard web forms application, we would normally create a Global.aspx that inherits UnitOfWorkApplication. Since we're using ASP.NET MVC, however, we don't necessarily want to go that route. As Michael Hanney notes on his post on MVC and Castle we can have our Global.asax inherit from UnitOfWorkApplication.

 

    public class GlobalApplication : UnitOfWorkApplication

    {

 

        public override void Application_Start(object sender, EventArgs e

        { 

            base.Application_Start(sender, e); 

            RegisterRoutes(RouteTable.Routes); 

        }

...

     }

If you know of another way to do this, please be sure to let me know. Also, the routing still works as it normally would -- we're just running this code first to instantiate the UnitOfWork.

In our controllers we can call our reference our Hibernate repositories and classes without specifying an ISession.

        public ActionResult InsertProductGroup(string Title)

        {

            ProductGroup pg = new ProductGroup();

            pg.Title = Title;

            Repository<ProductGroup>.Save(pg);

            UnitOfWork.Current.Flush();

            return RenderView("AddProductGroup");

        }

Notice we're still flushing our data -- but it makes the controllers a LOT cleaner. Imagine if we had to instantiate and clean up our session in each controller.

One further thing, the UnitOfWorkApplication supports both short and long conversations. I'm not going to go too much into that but if your application requires keeping objects around for a couple HTTP Requests before saving to the database Long Conversation may be the way to go. See Ayende's Wiki for more on this

NHibernate Query Generator
In the first post of this series we looked at what it takes to setup NHibernate Query Generator (NHQG from here out). Now we get to use it to make some really nice looking code (in a later post, however, we'll be using LINQ to NHibernate). If we've set up the tool as mentioned in the first post (listed earlier), all we have to do is run the tool and make sure the generated code is added to the project.

NHQG lets us use a fluent interface to set filters on our Hibernate queries; this results in code that, in my opinion, is very easy to write and understand later on. If we wanted to Find one Product with a specific title, our code would look something like this:

        public ActionResult ViewProduct(string ID)

        {

            var p = Repository<Product>.FindOne(Where.Product.Title == ID);

            if (p != null)

            {

                return RenderView("DisplayProduct",

                                  p); 

            }

            return RenderView("DisplayProduct");

        }

The Where.Product.Title == ID is all from the NHQG autogenerated code. Now we actually have something to show for all our configuration and setup work. Soon, we're going to take a look at using LINQ to NHibernate instead of NHQG. In the meantime, I have checked all the code in to my svn at Assembla. My standard disclaimer on demo code applies here too :) This is just demo code for the sake of example. Some of it is far from ideal but great for learning.

Check out / update with SubVersion from the following location: http://svn2.assembla.com/svn/NHibernateTest





RhinoCommons, NHibernate and ASP.NET MVC Part 2 - Configuration

May 20, 2008 by ryan

Following up on my last post, we're going to setup a project and get everything ready for the code (we'll be doing the coding very soon -- I promise).  First off, create a new MVC application (make sure you're using the latest preview from codeplex) and a new Class library. From here, you'd normally want to want to do some TDD to create your model but that's a little outside the scope of this example.

Add the references to Boo, Castle, NHibernate, RhinoCommons and Log4Net to the MVC application. In the class library, add Castle.ActiveRecord, Iesi.Collections, NHibernate, Rhino.Commons and Rhino.Commons.NHibernate. Switch over to your web.config file and Underneath the ConfigSections node add the following custom tags:

        <section name="activerecord" type="Castle.ActiveRecord.Framework.Config.ActiveRecordSectionHandler, Castle.ActiveRecord" />

        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >

            <section name="Rhino.Commons.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>

        </sectionGroup>   

Next add the specific custom tag properties somewhere after the </ConfigSections> : 

    <activerecord isWeb="true">

        <config>

            <add key="hibernate.connection.driver_class"

                value="NHibernate.Driver.SqlClientDriver" />

            <add key="dialect"

                value="NHibernate.Dialect.MsSql2005Dialect" />

            <add key="hibernate.connection.provider"

                value="NHibernate.Connection.DriverConnectionProvider" />

            <add key="hibernate.show_sql"

                value="false" />

            <add key="connection.connection_string" value="Data Source=___________;Initial Catalog=NHibernateTest;Integrated Security=True" />

        </config>

    </activerecord>

These active record settings should be pretty straight-forward but for more information on specific dialects or other properties check out the Castle's Configuration Reference. Be sure to swap out my Data Source and Initial Catalog settings with yours.

    <applicationSettings>

        <Rhino.Commons.Properties.Settings>

            <setting name="WindsorConfig"

                    serializeAs="String">

                <value>windsor.boo</value>

            </setting>

        </Rhino.Commons.Properties.Settings>

    </applicationSettings>

With this tag, we're telling Castle that we're going to configure Windsor with a boo file instead of an xml document. Ayende Rahien pointed out in the comments that this tag is no longer necessary as long as the file is named windsor.boo

Windsor Configuration With Boo 

Up until this point, we've been dealing with the web.config to configure our application -- now we want to configure Windsor but instead of using another xml file, we're going to use a boo file. What is Boo you might ask? According to wiki...

Boo is an object oriented, statically typed programming language developed starting in 2003, which seeks to make use of the Common Language Infrastructure support for Unicode, internationalization and web style applications, while using a Python-inspired syntax and a special focus on language and compiler extensibility. 

The mere fact that you can use a programming language instead of an XML file to configure Windsor is pretty sweet. I would be lying if I claimed to know boo very well, however, the Exesto and Hibernating-Forums samples (from the Rhino-Tools project) have enough information to get you up and running. I plan on learning boo well enought to create my own config files from scratch but in the mean time, here's what my boo file looks like (heavily influenced by the sample applications mentioned above)...

import Rhino.Commons

import System.Reflection

import Castle.Core

import Castle.Services.Transaction

import Castle.Facilities.AutomaticTransactionManagement

 

activeRecordAssemblies = ( Assembly.Load("ProductModelActiveRecord"), )

 

Component("active_record_repository", IRepository, ARRepository)

Component("active_record_unit_of_work",

    IUnitOfWorkFactory,

    ActiveRecordUnitOfWorkFactory,

    assemblies: activeRecordAssemblies )

Check out Ayende's comment for a more succinct way to register these components. As you might have noticed, I still have to set up the colors for boo files in Visual Studio :) What this file is doing is loading the assemblies and setting up the repository / unit of work (we'll see those in action in the next parts of this series). Your project configuration should be all set. Next time we will actually be writing some code so stick around for that. View Part Three - The Model









© 2008 Ryan Lanciaux :: powered by BlogEngine.NET