There are a number of needed infrastructure pieces in order to effectively work with a team of developers and stakeholders. If you’re using a technique like lean and want to provide CI (continuous integration) along with a Kanban board then you can use web sites that provide this infrastructure.

Scott HanselmanĀ  gave a talk at an OreDev in November 2009 titled, “Information Overload and Managing the Flow” that discusses some web sites for all the information that you receive on a daily basis. While his talk was specific to managing information the point is that there are free web sites for doing this.

Free is good but for a team it is no longer free. The free part is more geared for a single person working on a single project. This is ideal for trying out the web site and actually doing a small project.

What types of web sites would I use? For a team you need a few different web sites because I haven’t been able to locate an all-in-one web site that provides everything. If the team is going to be using a short iteration cycle approach and having the work exposed to the stakeholders you need to have four main areas covered.

You need some where to manage the short iteration cycles of the project. There are several ways to do this and for this discussion I will be using the Kanban approach. A web site I like is Agile Zen. The plan that fits best happens to be the most popular. This is the PRO plan at $29/month. It allows 10 projects, 10 collaborators, 10GB of file storage with email and IM notification and SSL encryption. This works good with a 3 person team and a few stakeholders.

The next area is you need somewhere to put the source code. The web site I like is Unfuddle. The thing I like about this web site is you can use either SVN or Git. The plan that I like is the Compact plan because it is the first plan to allow SSL. You really don’t want to be sending your code unencrypted. The plan provides 2GB of storage and 10 active projects for 20 people. In addition you get a dashboard, milestones and bug tracking.

So with source control and project management in place you now need a place to host the work. I currently use a hosting site for this blog but I don’t like the idea of using it to host the project. The reason is I want complete control of the project and many hosting web site charge more money for complete control. You can’t blame them because if you have control then you need to be hosted on dedicated server and not sharing a server. So I looked into cloud hosting. I haven’t made up my mind on what I want here. I’m mulling over two directions to take.

The first is using something like Amazon’s EC2. This service provides a resizable computing capacity in the cloud. Basically Amazon provides you with a server in the cloud.

The second option I’m considering is to use a VMWare hosting site. What this allows is a server that will have a VMWare image that can be used to deploy new web servers by deploying a new VMWare image. I like this and it may be the way I’ll go.

The important thing about a hosting site is that I have access to a database, preferably MS SQL Server. So no matter what way I decide I’ll need a db.

The last thing to consider is continuous integration. There are a couple of CI applications that I like, Hudson and TeamCity. Hudson it a java based application that runs in Tomcat and is built with a plug-in architecture. TeamCity is a CI and build management system offered by JetBrains (maker of ReSharper). What I really want is to get it free and put it on the hosting site.

That basically covers what I need have in place for a team developed project. There are other web sites to handle some of the things covered by Scott Hanselman and they may be needed too. These four areas address the infrastructure needs I have for team development.

This is fairly easy if you know the special sauce for encrypting Asp.Net web.config. You can use the built in functionality of Asp.Net. Go to Start => All Programs => Microsoft Visual Studio 2005/2008 => Visual Studio Tools =>Microsoft Visual Studio 2005/2008 Command Prompt.

Type in the following command (for using IIS):

aspnet_regiis.exe -pe "connectionString" -app "/<my virtual directory>"

You should see ‘Encrypting configuration section…" followed by "Succeeded!"

That is the first half. You then need to execute a second command to prevent, "Failed to decrypt using provider ‘RsaProtectedConfigurationProvider’. Error message from the provider: The RSA key container could not be opened".

aspnet_regiis.exe -pa "NetFrameworkConfigurationKey" "ASPNET"

You should see "Adding ACL for access to the RSA Key container…" followed by "Suceeded!"

Here are the two web sites I used to find this:

How to Encrypt connection string in web.config

Encrypting configuration files using protected configuration

Here is an interesting tidbit on using the lazy and outer-join property in Set mapping. A Set is a collection of unique items and is optimized for reading and writing. When using Set remember to assign a data type of HashSet in your class.

The lazy property is by default is set to true. If your code does a session.Get<T> and uses a foreach loop on the Set NHibernate will generate two select statements. Even if you change the lazy property to false you still get two select statements because NHibernate does not control how the Set is loaded. NHibernate in order to avoid the possibility of a Cartesian product generates the two select statements.

When the lazy property is false the Set is loaded when the .Get<T> is called. When the lazy property is set to true then the collection will only be loaded in the foreach loop.

If you want to load both the entity and the Set is a single SQL statement then you must use the outer-join property set to true. However, this is an expensive operations if you only need the Set loaded for certain situations. It is recommended that you don’t set the outer-join property to true.

What should you do? You should manage this at a higher level and not in the mapping. If you need all of the records in a Set to be loaded with the entity then you would use .SetFetchMode as part of your query. This would look something like this:

var myEntity = session.CreateCriteria<T>().SetFetchMode("U",FetchMode.Join).List();

where <T> is the class and U is the Set within the class.

This site is a screencast site that actually contains valuable information. I’m not saying that screencasts like Summer of NHibernate don’t have value. Summer of NHibernate is an excellent source for information for a good introduction to NHibernate.

What I like about TekPub is that use of domain experts on the subject. For Mastering NHibernate Rob Conery enlists the help of Oren Eini to dive much deeper into the material.

As the owners of the site put it, "Techbooks pretty much suck most of the time and you end up spending a whole mess of money when really what you want is to spend less time (and money) and learn from the people you trust."

If you’re looking for some excellent material then I urge you to check out TekPub.

I have Google’d this and tried to find an answer to this error message for weeks.  I got a Error with controller lot of hits from Google but I couldn’t find the definitive answer to correct the error. I’m using Rhino.Commons as part of the application along with Castle project and NHibernate.

So I started a solution from scratch adding the stack components as I went. I got Castle IoC and MonoRail displaying a simple page. I added the Spark View Engine and still got the home/index.spark page to render. When I added the Rhino.Commons components that is when I got the error. That is when I finally had the ‘aha’ moment. All of the Google hits never gave me any real clue about what the problem was. Here is the definitive solution to the problem.

Once Rhino.Commons along with the IoC class is introduced you need to register the controllers. I never put this rather obvious conclusion in place because I wasn’t thinking it was caused by the Rhino.Commons IoC class. I kept looking at the web.config file and the controllers that were being registered there.

Here is how I registered the controller by placing this in the global.asax.cs file.

IoC.Container.Register(
                AllTypes.Of<IController>().FromAssemblyNamed("your controllers"));

All of my controllers extend SmartDispatcherController.

What directory structure should be used for a web based project? There are no hard, Application Structure fast rules for this. The opinions vary and even my typical website project has changed. This is the latest project directory organization that I am using.

There are three projects: Genealogist, Genealogist.Tests and Genealogist.Web. Genealogist.Web is an Add => New Project => Visual C# => Web => ASP.NET Web Application. Don’t use Add => New Web Site => ASP.NET Web Site. This will not play well with the Global.asax/Global.asax.cs file. The other two are just C# class library projects.

The Genealogist.Web application has a special directory, FrameStack. FrameStack itself has three directories: NHibernate, Spark and Windsor. All three have a class named ConfigurationByConvention. As the name implies each of these classes provide methods for configuring the 3rd party libraries without using .XML files.

The Genealogist project has two directories: DomainModel and Queries. More directories may be added in the future as the project is developed. For now YAGNI indicates that this is the minimum of what is needed.

The DomainModel is based on using DDD principles and the entities, value objects, factories and repositories will be created there. The Queries directory is something I added after reading Udi Dahan’s Employing the Domain Model Pattern in MSDN Magazine. It is a separation of read-only query support from the full CRUD requirements found in the DomainModel.

Web References The 3rd party DLLs I used are from the Castle, NHibernate and Spark View Engine open source projects. I’ll add the Rhino.Commons and Fluent NHibernate when I start developing the Domain Model.

Anyway this is my current web site application structure. It uses Castle Windsor and MonoRail along with the Spark View Engine.

I have played with three different approaches to configuring Rhino.Commons, NHibernate and Windsor container for unit testing. I’ve spiked these three flavors in order to investigate building an infrastructure that is open to extension but closed to modification. I’m still in the process of doing my analysis but I now have 3 approaches to  play with.

My last blog entry showed how to use Rhino.Commons with an in memory SQLite database. The example also used Windsor container and it was my initial proof of concept. There are lots of blogs like this but I still had trouble figuring out how to make this rather easy approach work.

Since then I have been refactoring this approach and making it more closely follow the Open-Closed Principle first coined in 1988 by Bertrand Meyer in his book, Object-Oriented Software Construction. Prentice Hall. ISBN 0136290493. There is a very good article on the ObjectMentor blog about the OCP.

The first refactor I did was move away from using the hibernate.cfg.xml file and do it NHibernate configuration dynamically. I did this by creating a ConventionConfiguration class that uses NHibernate.Cfg.Environment static class properties.

using NHibernate;
using Rhino.Commons;
using Configuration = NHibernate.Cfg.Configuration;
using Environment=NHibernate.Cfg.Environment;

namespace CrawBuck.Commons.NHibernate {
    public class ConventionConfiguration : Configuration {
        private readonly Configuration configuration = new Configuration();

        public Configuration getConfiguration() { return configuration; }

        /// <summary>
        /// This is the wiring up point for NHibernate. This sets up the Environment properties for
        /// SQLite in memory database
        /// </summary>
        public void ConfigureNHiberateForSQLite() {
            IDictionary<string, string> properties = new Dictionary<string, string>();
            properties.Add(Environment.ConnectionProvider, "NHibernate.Connection.DriverConnectionProvider");
            properties.Add(Environment.ConnectionDriver, "NHibernate.Driver.SQLite20Driver");
            properties.Add(Environment.ConnectionString, "Data Source=:memory:;Version=3;New=True;");
            properties.Add(Environment.ShowSql, "true");
            properties.Add(Environment.Dialect, "NHibernate.Dialect.SQLiteDialect");
            properties.Add(Environment.ReleaseConnections, "on_close");
            properties.Add(Environment.ProxyFactoryFactoryClass, "NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle");
            configuration.SetProperties(properties);
        }
    }
}

This class will only do two things right now. It will dynamically configure NHibernate to use SQLite and it will return the NHibernate.Cfg.Configuration variable that holds these properties. For my infrastructure work I will later add a method to dynamically configure MS SQL Server database. Unit testing should be fast but there are times when you actually have to hit a real database. I call real database testing ‘integration database testing’ and don’t have my continuous integration build machine run this type of testing at check in. I do want to do integration database testing but I set the build for this to happen at about 4 hour intervals. Currently I’m using CruiseControl.NET but I’m going to be moving to Hudson.

The next change I made was to move the configuration of the Windsor container to a class of its own, BinsorlessUnitOfWorkApplication. This is an extension of Rhino.Commons.HttpModules.UnitOfWorkApplication.

using System;
using Castle.Facilities.FactorySupport;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using NHibernate;
using NHibernate.Cfg;
using Rhino.Commons;
using Rhino.Commons.HttpModules;
using Environment=System.Environment;

namespace CrawBuck.Commons.HttpModules {
    public class BinsorlessUnitOfWorkApplication : UnitOfWorkApplication {
        protected override IWindsorContainer CreateContainer(string windsorConfig) {
            //ignore windsor config string and create it empty…
            return new RhinoContainer();
        }

        /// <summary>
        /// This wires up the IoC Rhino/Windsor container for the basic facilities and components.
        /// </summary>
        public virtual void InitializeContainer() {
            Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
            IoC.Initialize(new WindsorContainer());
            IoC.Container
                .AddFacility<FactorySupportFacility>("factory.support")
                .AddFacility<RhinoTransactionFacility>("transaction")
                .Register(
                Component.For(typeof(IRepository<>)).ImplementedBy(typeof(NHRepository<>)),
                Component.For<IUnitOfWorkFactory>().ImplementedBy<NHibernateUnitOfWorkFactory>());
        }

        public void RegisterSessionFactory(Configuration configuration) {
            (IoC.Resolve<IUnitOfWorkFactory>() as NHibernateUnitOfWorkFactory).RegisterSessionFactory(configuration, configuration.BuildSessionFactory());
        }

        public ISessionFactory GetUnitOfWorkFactory() {
            return (IoC.Resolve<IUnitOfWorkFactory>() as NHibernateUnitOfWorkFactory).NHibernateSessionFactory;
        }
    }
}

I had to override the CreateContainer method in Rhino.Commons.HttpModules.UnitOfWork class to remove the need for the windsor.boo file. Once these two classes were in place I refactored the code from my last blog.

using System;
using System.Reflection;
using CrawBuck.Commons.HttpModules;
using CrawBuck.Commons.NHibernate;
using CrawBuck.Commons.Tests.Repository.Domain;
using NHibernate.Criterion;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
using Rhino.Commons;

namespace CrawBuck.Commons.Tests.Repository {
    [TestFixture]
    public class RhinoCommonsUnitOfWork {
        protected BinsorlessUnitOfWorkApplication unitOfWorkApplication = new BinsorlessUnitOfWorkApplication();
        protected ConventionConfiguration cc = new ConventionConfiguration();

        [SetUp]
        public void SetUp() {
            unitOfWorkApplication.InitializeContainer();
            cc.ConfigureNHiberateForSQLite();
            cc.getConfiguration().AddAssembly(Assembly.GetExecutingAssembly());
            unitOfWorkApplication.RegisterSessionFactory(cc.getConfiguration());
        }

        [Test]
        public void CanStartUnitOfWorkTest() {
            Customer customer = new Customer("Alan", "Buck");
            Guid guid = customer.Id;
            using(IUnitOfWork uow = UnitOfWork.Start()) {
                uow.BeginTransaction();
                new SchemaExport(cc.getConfiguration()).Execute(false, true, false, true, UnitOfWork.CurrentSession.Connection, null);
                Repository<Customer>.Save(customer);
                uow.TransactionalFlush();
                Customer loadCustomer = Repository<Customer>.Load(guid);
                Assert.AreEqual(loadCustomer.FirstName, "Alan");
                Assert.AreEqual(loadCustomer.LastName, "Buck");
                DetachedCriteria criteria = DetachedCriteria.For(typeof(Customer)).Add(Restrictions.Eq("Id", guid));
                Customer repositoryCustomer = Repository<Customer>.FindOne(criteria);
                Assert.AreEqual(repositoryCustomer.FirstName, "Alan");
                Assert.AreEqual(repositoryCustomer.LastName, "Buck");
            }
        }
    }
}

The following tests use either the Customer or Person classes.

using System;

namespace CrawBuck.Commons.Tests.Repository.Domain {
    public class Customer {
        private Guid id = Guid.NewGuid();
        private string firstName;
        private string lastName;

        public Customer() { }

        public Customer(string firstName, string lastName)
        {
            this.firstName = firstName;
            this.lastName = lastName;
        }
        public virtual Guid Id { get { return id; } set { id = value; } }
        public virtual string FirstName { get { return firstName; } set { firstName = value; } }
        public virtual string LastName { get { return lastName; } set { lastName = value; } }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-lazy=‘false’
    assembly=‘CrawBuck.Commons.Tests’
    namespace=‘CrawBuck.Commons.Tests.Repository.Domain’
    xmlns=‘urn:nhibernate-mapping-2.2′>
  <class name=‘Customer’>
    <id name="Id" column="Id">
      <generator class="assigned"/>
    </id>
    <property name="FirstName" />
    <property name="LastName"/>
  </class>
</hibernate-mapping>
using System;

namespace CrawBuck.Commons.Tests.Repository.Domain {
    public class Person {
        private Guid id = Guid.NewGuid();
        private string firstName;
        private string lastName;
        private int age;

        public Person() { }

        public Person(string firstName, string lastName, int age)
        {
            this.firstName = firstName;
            this.lastName = lastName;
            this.age = age;
        }

        public virtual Guid Id { get { return id; } set { id = value; } }
        public virtual string FirstName { get { return firstName; } set { firstName = value; } }
        public virtual string LastName { get { return lastName; } set { lastName = value; } }
        public virtual int Age { get { return age; } set { age = value; } }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-lazy=‘false’
    assembly=‘CrawBuck.Commons.Tests’
    namespace=‘CrawBuck.Commons.Tests.Repository.Domain’
    xmlns=‘urn:nhibernate-mapping-2.2′>
  <class name=‘Person’>
    <id name="Id" column="Id">
      <generator class="assigned"/>
    </id>
    <property name="FirstName" />
    <property name="LastName"/>
    <property name="Age" type="int"/>
  </class>
</hibernate-mapping>

The next refactor was to create a test base class that will allow the configuration of both the Windsor container and NHibernate using SQLite to be used by any unit test class.

using System;
using System.Reflection;
using CrawBuck.Commons.HttpModules;
using CrawBuck.Commons.NHibernate;
using CrawBuck.Commons.Tests.Repository.Domain;
using NHibernate.Criterion;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
using Rhino.Commons;

namespace CrawBuck.Commons.Tests.Repository {
    [TestFixture]
    public class RhinoCommonsUnitOfWork {
        protected BinsorlessUnitOfWorkApplication unitOfWorkApplication = new BinsorlessUnitOfWorkApplication();
        protected ConventionConfiguration cc = new ConventionConfiguration();

        [SetUp]
        public void SetUp() {
            unitOfWorkApplication.InitializeContainer();
            cc.ConfigureNHiberateForSQLite();
            cc.getConfiguration().AddAssembly(Assembly.GetExecutingAssembly());
            unitOfWorkApplication.RegisterSessionFactory(cc.getConfiguration());
        }

        [Test]
        public void CanStartUnitOfWorkTest() {
            Customer customer = new Customer("Alan", "Buck");
            Guid guid = customer.Id;
            using(IUnitOfWork uow = UnitOfWork.Start()) {
                uow.BeginTransaction();
                new SchemaExport(cc.getConfiguration()).Execute(false, true, false, true, UnitOfWork.CurrentSession.Connection, null);
                Repository<Customer>.Save(customer);
                uow.TransactionalFlush();
                Customer loadCustomer = Repository<Customer>.Load(guid);
                Assert.AreEqual(loadCustomer.FirstName, "Alan");
                Assert.AreEqual(loadCustomer.LastName, "Buck");
                DetachedCriteria criteria = DetachedCriteria.For(typeof(Customer)).Add(Restrictions.Eq("Id", guid));
                Customer repositoryCustomer = Repository<Customer>.FindOne(criteria);
                Assert.AreEqual(repositoryCustomer.FirstName, "Alan");
                Assert.AreEqual(repositoryCustomer.LastName, "Buck");
            }
        }
    }
}

Here is a unit test class that takes advantage of the RepositoryTestsBase class.

using System;
using CrawBuck.Commons.Tests.ForTesting;
using CrawBuck.Commons.Tests.Repository.Domain;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
using Rhino.Commons;

namespace CrawBuck.Commons.Tests.Repository {
    [TestFixture]
    public class RepositoryTest : RepositoryTestsBase {
        private ISession session;
        private Person person;
        private Guid guid;

        [TestFixtureSetUp]
        public void TestFixtureSetUp() {
            OneTimeTestInitialize();
        }

        [SetUp]
        public void SetUp() {
            person = new Person("Alan", "Buck", 62);
            guid = person.Id;
        }

        [Test]
        public void ShouldCreateRepositoryTest() {
            session = CreateSession();
            session.Save(person);
            session.Flush();
            session.Clear();
            Person loadPerson = session.Load<Person>(guid);
            Assert.AreEqual(loadPerson.FirstName, "Alan");
            Assert.AreEqual(loadPerson.LastName, "Buck");
            Assert.AreEqual(loadPerson.Age, 62);
            session.Dispose();
        }

        [Test]
        public void ShouldCreateUsingIRepositoryTest() {
            using (IUnitOfWork uow = UnitOfWork.Start()) {
                new SchemaExport(configuration).Execute(false, true, false, true, UnitOfWork.CurrentSession.Connection, null);
                Repository<Person>.Save(person);
                uow.TransactionalFlush();
                DetachedCriteria criteria = DetachedCriteria.For(typeof(Person)).Add(Restrictions.Eq("Id", guid));
                Person loadPerson = Repository<Person>.FindOne(criteria);
                Assert.AreEqual(loadPerson.FirstName, "Alan");
                Assert.AreEqual(loadPerson.LastName, "Buck");
                Assert.AreEqual(loadPerson.Age, 62);
            }
        }

        [TearDown]
        public void TearDown() {}
    }
}

That covers two of the approaches to using Rhino.Commons, NHibernate and the Windsor container. The last approach is to use FluentNHibernate. I’m not using the ClassMap of FluentNHibernate. This still uses the .hbm.xml files.

using System;
using System.IO;
using System.Reflection;
using Castle.Windsor;
using CrawBuck.Commons.HttpModules;
using CrawBuck.Commons.NHibernate;
using CrawBuck.Commons.Tests.Repository.Domain;
using FluentNHibernate.AutoMap;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
using Rhino.Commons;
using Configuration = NHibernate.Cfg.Configuration;
using Environment=NHibernate.Cfg.Environment;

namespace CrawBuck.Commons.Tests.Repository {
    [TestFixture]
    public class FluentNHibernate {
        private readonly BinsorlessUnitOfWorkApplication unitOfWorkApplication = new BinsorlessUnitOfWorkApplication();
        private Configuration config;
        private readonly ConventionConfiguration cc = new ConventionConfiguration();

        [SetUp]
        public void SetUp() {
            unitOfWorkApplication.InitializeContainer();
            cc.ConfigureNHiberateForSQLite();
            config = cc.getConfiguration();
            config.AddAssembly(Assembly.GetExecutingAssembly());
            CreateRhinoSessionFactoryForSQLite();
        }

        [Test]
        public void CanStartUnitOfWorkTest() {
            Customer customer = new Customer("Alan", "Buck");
            Guid guid = customer.Id;
            using (IUnitOfWork uow = UnitOfWork.Start()) {
                uow.BeginTransaction();
                new SchemaExport(config).Execute(false, true, false, true, UnitOfWork.CurrentSession.Connection, null);
                Repository<Customer>.Save(customer);
                uow.TransactionalFlush();
                Customer loadCustomer = Repository<Customer>.Load(guid);
                Assert.AreEqual(loadCustomer.FirstName, "Alan");
                Assert.AreEqual(loadCustomer.LastName, "Buck");
                DetachedCriteria criteria = DetachedCriteria.For(typeof(Customer)).Add(Restrictions.Eq("Id", guid));
                Customer repositoryCustomer = Repository<Customer>.FindOne(criteria);
                Assert.AreEqual(repositoryCustomer.FirstName, "Alan");
                Assert.AreEqual(repositoryCustomer.LastName, "Buck");
            }
        }

        private void CreateRhinoSessionFactoryForSQLite() {
            IPersistenceConfigurer configurer = SQLiteConfiguration.Standard.InMemory().ShowSql();
            ISessionFactory sessionFactory = Fluently.Configure(config).Database(configurer).Mappings(m => m.FluentMappings.AddFromAssemblyOf<Customer>()).BuildSessionFactory();
            (Rhino.Commons.IoC.Resolve<IUnitOfWorkFactory>() as NHibernateUnitOfWorkFactory).RegisterSessionFactory(config, sessionFactory);
        }
    }
}

You will notice that I have a CreateRhinoSessionFactoryForSQLite method in this test class. It’s there because I’m lazy and it’s late. Maybe in a future blog I will refactor this unit test to use ClassMap and move the CreateRhinoSessionFactoryForSQLite to the BinsorlessUnitOfWorkApplication class. I’m still moving up the learning curve on FluentNHibernate and have only the basic understanding of what all this OSS project has to offer.

There are many examples of writing unit test for NHibernate on the internet. Most of them show how to do this using session factory, session and MS SQL Server. I wanted to do this using Rhino.Commons and SQLite. Here is the code.

using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Reflection;
using Castle.Windsor;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Tool.hbm2ddl;
using NUnit.Framework;
using Rhino.Commons;
using Rhino.Mocks;

namespace CrawBuck.Commons.Tests.Repository {
    [TestFixture]
    public class RhinoCommonsUnitOfWork {
        protected Configuration configuration;

        [SetUp]
        public void SetUp() {
            System.Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
            WindsorContainer container = new WindsorContainer(Path.GetFullPath(@”RepositoryWindsor.cfg.xml”));
            configuration = new Configuration();
            configuration.Configure();
            Rhino.Commons.IoC.Initialize(container);
        }

        [Test]
        public void CanStartUnitOfWorkTest() {
            Customer customer = new Customer(“Alan”, “Buck”);
            Guid guid = customer.Id;
            using(IUnitOfWork uow = UnitOfWork.Start()) {
                uow.BeginTransaction();
                new SchemaExport(configuration).Execute(false, true, false, true, UnitOfWork.CurrentSession.Connection, null);
                Repository<Customer>.Save(customer);
                uow.TransactionalFlush();
                Customer loadCustomer = Repository<Customer>.Load(guid);
                Assert.AreEqual(loadCustomer.FirstName, “Alan”);
                Assert.AreEqual(loadCustomer.LastName, “Buck”);
                DetachedCriteria criteria = DetachedCriteria.For(typeof(Customer)).Add(Restrictions.Eq(“Id”, guid));
                Customer repositoryCustomer = Repository<Customer>.FindOne(criteria);
                Assert.AreEqual(repositoryCustomer.FirstName, “Alan”);
                Assert.AreEqual(repositoryCustomer.LastName, “Buck”);
            }
        }
    }

    public class Customer {
        private Guid id = Guid.NewGuid();
        private string firstName;
        private string lastName;

        public Customer() { }

        public Customer(string firstName, string lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
        public virtual Guid Id { get { return id; } set { id = value; } }
        public virtual string FirstName { get { return firstName; } set { firstName = value; } }
        public virtual string LastName { get { return lastName; } set { lastName = value; } }
    }
}

I’ve included the using statements because I find that without them you’re never sure what DLLs you need. This was not easy for me to figure out but once I got it to work it was very simple. In the SetUp I create a Windsor container, set up my NHibernate.Cfg.Configuration variable and initialize the Rhino.Commons.IoC with the WindsorContainer. This is most of the configuration that I need. In the CanStartUnitOfWorkTest I create a Customer object and then use it inside of Rhino.Commons.UnitOfWork. The last piece of configuration that I do is to use SchemaExport to create an in memory database with SQLite with the UnitOfWork context. As the code shows I save the Customer object using Rhino.Commons.Repository<Customer>.Save. I retrieve it back out of the database using Rhino.Commons.Repository<Customer>.Load and Rhino.Commons.Repository<Customer>.FindOne.

I use the Windsor.cfg.xml file to configure the container.

<?xml version=“1.0″ encoding=“utf-8″ ?>
<configuration>
  <components>
    <component id=“nhibernate.repository”
                   service =“Rhino.Commons.IRepository`1, Rhino.Commons.NHibernate”
                   type=“Rhino.Commons.NHRepository`1, Rhino.Commons.NHibernate”/>
    <component id=“nhibernate.unit-of-work.factory”
                   service =“Rhino.Commons.IUnitOfWorkFactory, Rhino.Commons.NHibernate”
                    type=“Rhino.Commons.NHibernateUnitOfWorkFactory, Rhino.Commons.NHibernate”/>
  </components>
</configuration>

I use the hibernate.cfg.xml file to configure NHibernate.

<?xml version=“1.0″ encoding=“utf-8″ ?>
<hibernate-configuration  xmlns=“urn:nhibernate-configuration-2.2″ >
  <session-factory>
    <!– properties –>
    <property name=“connection.provider”>NHibernate.Connection.DriverConnectionProvider</property>
    <property name=“connection.driver_class”>NHibernate.Driver.SQLite20Driver</property>
    <property name=“connection.connection_string”>Data Source=:memory:;Version=3;New=True;</property>
    <property name=“show_sql”>true</property>
    <property name=“dialect”>NHibernate.Dialect.SQLiteDialect</property>
    <property name=“proxyfactory.factory_class”>NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
    <property name=“connection.release_mode”>on_close</property>

    <mapping assembly=“CrawBuck.Commons.Tests” />
  </session-factory>
</hibernate-configuration>

That is all there is to do this.

My last post was about using Ext.extend to render my web pages. Now I’ll show how I use pre-configured classes to render my Genealogist application. This is the default.brail file I’m using for my default layout page.

 

 

   1: <html>
   2: <head>
   3:     <meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″>
   4:     <link rel=”stylesheet” type=”text/css” href=”../../Content/extJS/resources/css/ext-all.css” />
   5:     <link rel=”stylesheet” type=”text/css” href=”../../Content/extJS/resources/css/genealogist.css” />
   6:     <script type=”text/javascript” src=”../../Content/extJS/adapter/ext/ext-base.js”></script>
   1:
   2:     <script type=“text/javascript” src=“../../Content/extJS/ext-all-debug.js”>
   1: </script>
   2:     <script type=“text/javascript” src=“../../Content/js/layout/GenealogistFunctions.js”>
   1: </script>
   2:     <script type=“text/javascript” src=“../../Content/js/layout/GenealogistTab.js”>
   1: </script>
   2:     <script type=“text/javascript” src=“../../Content/js/default.js”>

</script>

   7:
   8:     <title>CrawBuck Genealogist</title>
   9: </head>
  10: <body>
  11:     <div id=”west”></div>
  12:     <div id=”north”>Genealogist</div>
  13:     <div id=”center2″></div>
  14:     <div id=”center1″></div>
  15:     <div id=”south”>Copyright 2008 CrawBuck</div>
  16: </body>
  17: </html>

I start by setting up the necessary ExtJS files: ext-all.css, genealogist.css, ext-base.js and ext-all-debug.js. These are the normal files that are required by ExtJS. The next file, GenealogistFunctions.js is the first pre-configured class. In this file I’m using an Ext.Panel to create my pre-configured class. This panel is going to be an accordion panel that is located in the ‘west’ region of the Ext.Viewport. The code looks like this:

 

 

   1: Ext.ns(‘Ext.ux.Genealogist’);
   2:
   3: Ext.ux.Genealogist.GenealogistFunctions = Ext.extend(Ext.Panel, {
   4:     region:‘west’,
   5:     id:‘west-panel’,
   6:     title:‘Genealogist Functions’,
   7:     split:true,
   8:     width: 200,
   9:     minSize: 175,
  10:     maxSize: 400,
  11:     collapsible: true,
  12:     margins:‘0 0 0 5′,
  13:     layout:‘accordion’,
  14:     layoutConfig:{animate:true},
  15:
  16:     initComponent: function(){
  17:         Ext.apply(this, {
  18:             items:[{
  19:                 title:‘Person’,
  20:                 html:‘<p>Manages person in here.</p>’,
  21:                 border:false,
  22:                 iconCls:‘nav’
  23:             },{
  24:                 title:‘Life Events’,
  25:                 html:‘<p>Manages life events in here.</p>’,
  26:                 border:false,
  27:                 iconCls:’settings’
  28:             },{
  29:                 title:‘Family’,
  30:                 html:‘<p>Manages family in here.</p>’,
  31:                 border:false,
  32:                 iconCls:’settings’
  33:             },{
  34:                 title:‘Search’,
  35:                 html:‘<p>Searching in here.</p>’,
  36:                 border:false,
  37:                 iconCls:’settings’
  38:             },{
  39:                 title:‘Reports’,
  40:                 html:‘<p>Reporting in here.</p>’,
  41:                 border:false,
  42:                 iconCls:’settings’
  43:             },{
  44:                 title:‘Lists’,
  45:                 html:‘<p>Listing in here.</p>’,
  46:                 border:false,
  47:                 iconCls:’settings’
  48:             }]
  49:         });
  50:
  51:         Ext.ux.Genealogist.GenealogistFunctions.superclass.initComponent.apply(this, arguments);
  52:     },
  53:
  54:     onRender:function() {
  55:         Ext.ux.Genealogist.GenealogistFunctions.superclass.onRender.apply(this, arguments);
  56:     }
  57:
  58: }); // eo GenealogistFunctions
  59:
  60: Ext.reg(‘genealogistFunctions’, Ext.ux.Genealogist.GenealogistFunctions);

The next file in the web page is GenealogistTab.js. This is an Ext.TabPanel that is located in the ‘center’ region of the Ext.Viewport. The code looks like this:

 

 

   1: Ext.ns(‘Ext.ux.Genealogist’);
   2:
   3: Ext.ux.Genealogist.GenealogistTab = Ext.extend(Ext.TabPanel,{
   4:     region:‘center’,
   5:     deferredRender:false,
   6:     activeTab:0,
   7:
   8:     initComponent: function(){
   9:         Ext.apply(this, {
  10:             items:[{
  11:                 contentEl:‘center1′,
  12:                 title: ‘Add Person’,
  13:                 closable:true,
  14:                 autoScroll:true
  15:             },{
  16:                 contentEl:‘center2′,
  17:                 title: ‘Edit Person’,
  18:                 autoScroll:true
  19:             }]
  20:         });
  21:
  22:         Ext.ux.Genealogist.GenealogistTab.superclass.initComponent.apply(this, arguments);
  23:     },
  24:
  25:     onRender: function() {
  26:         Ext.ux.Genealogist.GenealogistTab.superclass.onRender.apply(this, arguments);
  27:     }
  28:
  29: }); // eo Ext.Genealogist.genealogistTab
  30:
  31: Ext.reg(‘genealogistTab’, Ext.ux.Genealogist.GenealogistTab);

The HomeController class for Monorail is brain dead at this time. All it does is pair the default layout with the Genealogist view. The code looks like this:

 

 

   1: using Castle.MonoRail.Framework;
   2:
   3: namespace Genealogist.Controllers {
   4:     public class HomeController : SmartDispatcherController {
   5:         public void Index() {}
   6:
   7:         [Layout(“default”)]
   8:         public void Genealogist() {}
   9:     }
  10: }

The one file that ties them all together is the default.js file that contains the Ext.onReady function. Also notice that the default.js file comes after the GenealogistFunctions.js and GenealogistTab.js. The ordering is important because the default.js file uses the two pre-configured classes, genealogistFunctions and genealogistTab. The code looks like this:

 

 

   1: Ext.BLANK_IMAGE_URL = ‘../../Content/images/s.gif’;
   2: Ext.namespace(‘Ext.ux.Genealogist’)
   3:
   4: Ext.onReady(function() {
   5:     var viewPort = new Ext.Viewport({
   6:         layout:‘border’,
   7:         items:[
   8:             new Ext.BoxComponent({ // raw
   9:                 region:‘north’,
  10:                 el: ‘north’,
  11:                 height:100,
  12:                 style:‘background-image:url(../Content/images/BannerBackground.png);background-repeat:repeat-x;border:solid 1px #1D6241;text-align:right;vertical-align:middle;padding-right:10px;font-family:Georgia;font-size:75px;color:#ED7014;’
  13:             }),
  14:             new Ext.BoxComponent({
  15:                 region:’south’,
  16:                 el: ’south’,
  17:                 height:25,
  18:                 style:‘background-image:url(../Content/images/FooterBackground.png);background-repeat:repeat-x;border:solid 1px #1D6241;text-align:center;font-family:Verdana;font-weight:bold;color:#ED7014;padding-top:5px;’
  19:             }),{xtype:‘genealogistFunctions’},
  20:                {xtype:‘genealogistTab’} // end of TabPanel
  21:         ] // end of items
  22:     }); // end of Viewport
  23: }); // eo function onReady

What I like about this is that the default.js file is small and easy to understand. Leveraging the two pre-configured classes in the Ext.Viewport are a matter of using xtype and placing the two in {xtype:’genealogistFunctions’} and {xtype:’genealogistTab’}. Now that is a lot easier to read then having all the ExtJS code in one monolithic file.

I’ve been busy on a SP1 release for the my day job and haven’t spent much time on figuring out ExtJS. I’ve blogged before about how I am having difficulty coming up to speed on this product. I have been trying for weeks to use the pre-configured concept of ExtJS without success. ExtJS’s examples show very simple usages and I’m trying to make use more complex usages. So it has been a lot of trial and run. I’ve finally got the accordion panel to work outside of my Genealogist layout and I’m going to try and incorporate it. Here is how it looks:

Wizard1

This has the accordion panel on the left and the right panel can be used for multiple purposes. The goal is to have the accordion panel expose the various functions of the Genealogist project and the right panel will provide the implementation of the functions. I’m going to incorporate this into the Genealogist layout:

Wizard2

I’m using the pre-configured classes that are talked about here. The general pattern is:

   1: MyScope = Ext.extend(Ext.form.ComboBox, {
   2:     // configurables
   3:     // anything what is here can be configured from outside
   4:      border:false
   5:  
   6:     // {{{
   7:     ,initComponent:function() {
   8:         // {{{
   9:         Ext.apply(this, {
  10:             // anything here, e.g. items, tools or buttons arrays,
  11:             // cannot be changed from outside
  12:         }); // e/o apply
  13:         // }}}
  14:  
  15:         // call parent
  16:         MyScope.superclass.initComponent.apply(this, arguments);
  17:  
  18:         // after parent code here, e.g. install event handlers
  19:  
  20:     } // e/o function initComponent
  21:     // }}}
  22:     // {{{
  23:     ,onRender:function() {
  24:  
  25:         // before parent code
  26:  
  27:         // call parent
  28:         MyScope.superclass.onRender.apply(this, arguments);
  29:  
  30:         // after parent code, e.g. install event handlers on rendered components
  31:         
  32:     } // e/o function onRender
  33:     // }}}
  34:     
  35:     // any other added/overrided methods
  36:  
  37: }); // e/o extend
  38:  
  39: // register xtype
  40: Ext.reg(‘mycomponentxtype’, MyScope); 

I’m using a single file for the AccordionPanel class and the code is:

   1: Ext.ux.AccordionPanel = Ext.extend(Ext.Panel, {
   2:     region:‘west’,       
   3:     margins:‘5 0 5 5′,
   4:     split:true,
   5:     width: 210,
   6:     layout:‘accordion’,
   7:         
   8:     initComponent: function(){
   9:         Ext.apply(this, {
  10:             items:[{
  11:                 title: ‘Accordion Item 1′,
  12:                 html: ‘&lt;empty panel&gt;’,
  13:                 xtype: ‘panel’
  14:             },{
  15:                 title: ‘Accordion Item 2′,
  16:                 html: ‘&lt;empty panel&gt;’,
  17:                 xtype: ‘panel’
  18:             },{
  19:                 title: ‘Accordion Item 3′,
  20:                 html: ‘&lt;empty panel&gt;’,
  21:                 xtype: ‘panel’
  22:             },{
  23:                 title: ‘Accordion Item 4′,
  24:                 html: ‘&lt;empty panel&gt;’,
  25:                 xtype: ‘panel’
  26:             },{
  27:                 title: ‘Accordion Item 5′,
  28:                 html: ‘&lt;empty panel&gt;’,
  29:                 xtype: ‘panel’
  30:             }]
  31:         });
  32:         
  33:         Ext.ux.AccordionPanel.superclass.initComponent.apply(this, arguments);
  34:     },
  35:     
  36:     onRender:function(){
  37:         Ext.ux.AccordionPanel.superclass.onRender.apply(this, arguments);
  38:     }
  39:  
  40: });
  41:  
  42: Ext.reg(‘accordionPanel’, Ext.ux.AccordionPanel);

The .brail page looks like this:

   1: <html>
   2: <head>
   3:     <title>Accordion Layout</title>
   4:     <link rel=”stylesheet” type=”text/css” href=”../../Content/ExtJS/resources/css/ext-all.css”/>
   5:  
   6:     <!– GC –>
   7:     <!– LIBS –>
   8:     <script type=”text/javascript” src=”../../Content/ExtJS/adapter/ext/ext-base.js”></script>
   1:  
   2:     <!– ENDLIBS –>
   3:  
   4:     <script type=“text/javascript” src=“../../Content/ExtJS/ext-all-debug.js”>
   1: </script>
   2:     <script type=“text/javascript” src=“../../Content/ExtJS/js/AccordionPanel.js”>
   1: </script>
   2:  
   3:     <style type=“text/css”>
   4:         html, body {
   5:             font: normal 12px verdana;
   6:             margin: 0;
   7:             padding: 0;
   8:             border: 0 none;
   9:             overflow: hidden;
  10:             height: 100%;
  11:         }
  12:         .empty .x-panel-body {
  13:             padding-top:20px;
  14:             text-align:center;
  15:             font-style:italic;
  16:             color: gray;
  17:             font-size:11px;
  18:         }
  19:     </style>
  20:     <script type=“text/javascript”>
  21:         Ext.onReady(function() {
  22:                         
  23:             var viewport = new Ext.Viewport({
  24:                 layout:‘border’,
  25:                 renderTo:Ext.getBody(),
  26:                 items:[{
  27:                     xtype:‘accordionPanel’
  28:                 },{
  29:                     region:‘center’,
  30:                     margins:‘5 5 5 0′,
  31:                     cls:‘empty’,
  32:                     bodyStyle:‘background:#f1f1f1′,
  33:                     html:‘<br/><br/>&lt;empty center panel&gt;’
  34:                 }]
  35:             });
  36:             
  37:         });
  38:     

</script>

   9: </head>
  10: <body>
  11:  
  12: </body>
  13: </html>

I can’t believe it has taken me this long to do this. I still don’t understand ExtJS very well but I’m slowly picking up pieces. My hope is that starting this week I will be able to spend my day job increasing my understanding of ExtJS.

Next Page »