How Dovetail uses NHibernate with StructureMap

A quick note here, this article shows features of StructureMap that are only available in the very latest 2.5.4 release available on sourceforge.  I’ve uploaded the finished binaries, but haven’t made a formal announcement because I’m a couple weeks away from having the docs updated (and yes, StructureMap *is* actually well documented, thank you).  My friend Weston Binford published his take on StructureMap / NHibernate bootstrapping and some on managing transactional boundaries with NHibernate in a web application.  He’s been constantly nagging me to write *this* post because we do things very differently with some of the newer features in StructureMap that I haven’t documented yet (and frankly, you should thank me for dogfooding this stuff and playing whack-a-mole with memory leak bugs before inflicting it upon the world). 

This is *our* approach and not a canonical example of how to do everything.  It’s working for us at the moment is the best that I can really say.  The performance is good enough for us, but I won’t claim that it’s been tuned yet.  In writing this it has definitely occurred to me that, yes, this does seem pretty complicated.  There are a lot of moving parts, but at least every individual moving part is simple by itself.  I’m used to seeing software designs as a series of fine grained objects fulfilling narrow roles that collaborate with each other.  I’m very aware that other developers think it’s simpler to have fewer, but blockier moving parts.  And no, I don’t think the complexity is a flaw in NHibernate because I think all of the application lifecycle issues apply to all ORM tools.

Ok, here we go, we need to talk about:

  1. Tooling
  2. Bootstrapping NHibernate
  3. Configuring NHibernate in StructureMap
  4. Session Management
  5. Runtime Usage of NHibernate
  6. Our Workflow

 

Tooling

For tooling, Dovetail generally runs on the trunk of StructureMap at all times (dogfooding, and a lot of my StructureMap dev work is driven by Dovetail needs).  Beyond that, we use:

  1. NHibernate 2.1.0.1003
  2. Linq for NHibernate – We frankly haven’t had any issues with its limitations.  Most of our querying is by primary key or by simple queries for whole entities, so advanced Linq usage just isn’t something we need.  We do have our own little bit of tooling around the old ICriteria stuff in the few places we do projections.
  3. Fluent NHibernate 0.1.0443.  We don’t use the auto mapping, but we have gotten significant usage out of the conventions all the same.
  4. The FubuMVC Reboot.  This is significant for the section on session management.  The approach we use will not apply to ASP.Net MVC or WebForms (dunno about MonoRail).

 

Bootstrapping NHibernate

The first thing you generally have to do with NHibernate is to figure out how you’re going to create the NHibernate SessionFactory object and how you’ll feed configuration data to the SessionFactory in your architecture.  When I started using NHibernate 4-5 years ago I quickly settled on a role in the system I call “ISessionSource” that generally manages the creation of a SessionFactory object and uses that object to create ISession objects.  The signature of ISessionSource is this:

    public interface ISessionSource

    {

        ISession CreateSession();

        void BuildSchema();

    }

 

As you can see, it only has two methods.  CreateSession() is obvious.  BuildSchema() invokes the HBM2DDL tool to completely rebuild the database schema off of the NHibernate mappings (more on this below).  The real implementation of ISessionSource for us is of course, NHibernateSessionSource (shown heavily elided):

    public class NHibernateSessionSource : ISessionSource

    {

        private readonly DatabaseSettings _databaseSettings;

        private readonly object _factorySyncRoot = new object();

        private ISessionFactory _sessionFactory;

        private Configuration _configuration;

 

        public NHibernateSessionSource(DatabaseSettings databaseSettings)

        {

            if (_sessionFactory != null) return ;

 

            lock (_factorySyncRoot)

            {

                if (_sessionFactory != null) return;

 

                _databaseSettings = databaseSettings;

                _configuration = AssembleConfiguration(null);

                _sessionFactory = _configuration.BuildSessionFactory();

            }

        }

 

        public Configuration AssembleConfiguration(string mappingExportPath)

        {

            // other stuff off stage

 

            // We use Fluent NHibernate’s Fluently.Configure() to setup conventions, attach event listeners,

            // configure the properties from the DatabaseSettings object like the connection string, and

            // the list of IDomainMap objects passed in the constructor function that define the mappings

            return Fluently.Configure()

                .Database(new DovetailPersistenceConfigurer(nhibernateProperties))

                .ExposeConfiguration(config=>

                {

                    var listener = new NHibernateSaveListener();

 

                    config.EventListeners.PreInsertEventListeners = new IPreInsertEventListener[]{listener};

                    config.EventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[]{listener};

                })

                .Mappings(m =>

                {

 

                    m.FluentMappings.AddFromAssemblyOf<DomainEntity>();

                    m.FluentMappings.ConventionDiscovery.Setup(convention =>

                    {

                        // Set up the Fluent NHibernate conventions

                        convention.Add<TimeZoneInfoTypeConvention>();

                        convention.Add<ManyToManyConvention>();

 

                    });

                }).BuildConfiguration();

        }

 

        #region ISessionSource Members

 

        public ISession CreateSession()

        {

            return _sessionFactory.OpenSession();

        }

 

        public void BuildSchema()

        {

            ISession session = CreateSession();

            IDbConnection connection = session.Connection;

 

            Dialect dialect = Dialect.GetDialect(_databaseSettings.GetProperties());

            string[] drops = _configuration.GenerateDropSchemaScript(dialect);

            executeScripts(drops, connection);

 

            string[] scripts = _configuration.GenerateSchemaCreationScript(dialect);

            executeScripts(scripts, connection);

        }

 

        #endregion

 

        private static void executeScripts(string[] scripts, IDbConnection connection)

        {

            foreach (string script in scripts)

            {

                IDbCommand command = connection.CreateCommand();

                command.CommandText = script;

                command.ExecuteNonQuery();

            }

        }

    }

 

We simply embed Fluent NHibernate (FNH) ClassMap classes directly into the same assembly that holds the NHibernateSessionSource object.  The call to m.FluentMappings.AddFromAssemblyOf<DomainEntity>(); scans the executing assembly for any classes that inherit from ClassMap<T> from FNH and add them to the NHibernate Configuration object for use in constructing the SessionFactory object behind the scenes.  Now, the DatabaseSettings class contains all of the metadata that our NHibernate SessionFactory needs.  It’s really just a simple data bag class:

    public class DatabaseSettings

    {

        public string Provider { get; set; }

        public string Driver { get; set; }

        public string Dialect { get; set; }

        public bool UseOuterJoin { get; set; }

        [ConnectionString]

        public string ConnectionString { get; set; }

        public bool ShowSql { get; set; }

        public string ProxyFactory { get; set; }

 

        // simple solution for now

        public IDictionary<string, string> GetProperties()

        {

            if (Provider.IsEmpty()) throw new ApplicationException(“DatabaseSettings unavailable. Make sure your application configuration file has appSetting entries for the necessary DatabaseSettings properties.”);

            var properties = new Dictionary<string, string>

                                {

                                    {“connection.provider”, Provider},

                                    {“connection.driver_class”, Driver},

                                    {“dialect”, Dialect},

                                    {“use_outer_join”, UseOuterJoin.ToString()},

                                    {“connection.connection_string”, ConnectionString},

                                    {“show_sql”, ShowSql.ToString()},

                                    {“proxyfactory.factory_class”, ProxyFactory}

 

                                };

            return properties;

        }

    }

In the interest of me finishing this post before midnight, I’m going to skip out on how DatabaseSettings is resolved from the app settings config, but let’s just say that StructureMap “knows” how to build DatabaseSettings and therefore can inject it into the constructor function of any object that needs DatabaseSettings.

 

Configuring NHibernate in StructureMap

Regardless of which IoC tool you choose (apparently there are others beside StructureMap), you will consistently want to manage the NHibernate SessionFactory object as a singleton instance in your container.  This is important because the ISessionFactory is very expensive in resources to bootstrap.  You only want to do this once.  The second thing you want to do is to teach the container how to resolve an object instance of the ISession object.  The entire configuration of NHibernate objects in StructureMap is shown below as part of a StructureMap Registry in our codebase called “CoreRegistry”:

    public class CoreRegistry : Registry

    {

        public const string IN_MEMORY_PROFILE = “InMemory”;

 

        public CoreRegistry()

        {

            setupNHibernate();

        }

 

        private void setupNHibernate()

        {

            ForSingletonOf<ISessionSource>().Use<NHibernateSessionSource>();

            For<ISession>().Use(c =>

            {

                var transaction = (NHibernateTransactionBoundary)c.GetInstance<ITransactionBoundary>();

                return transaction.Session;

            });

 

            For<IUniqueIdentifierService>().Use<NHibernateUniqueIdentifierService>();

            For<ITransactionBoundary>().Use<NHibernateTransactionBoundary>();

 

            For<IRepository>().Use<Repository>();

        }

 

    } 

For StructureMap veterans, this is the new streamlined Registry DSL found in 2.5.4.  The key points here are that ISessionSource is registered with the singleton lifecycle in StructureMap so that there is only one of these very expensive objects created for the lifetime of the application.  Look at how the “ISession” object is resolved by StructureMap by invoking a Lambda function.  Our ISession lifecycle is partially controlled by the ITransactionalBoundary/NHibernateTransactionalBoundary class that I’ll describe in detail in the next section.  Our Repository class, and any other classes that directly touch the NHibernate ISession, simply need to expose a constructor argument for “ISession” and StructureMap will happily invoke the Lambda function above to create and return an ISession:

        public Repository(ISession session, ILogger logger)

        {

            _session = session;

            _logger = logger;

        }

 

Session Management

Okay, this is the part of our solution that I don’t particularly care for – except that it works.  We’re building a web application that involves a lot of very short atomic transactions.  We do not have any significant need for nested transactions or unit of work type implementations.  That being said, we have three basic needs for NHibernate usage in a web request:

  1. We need to start a single ISession for each unique web request
  2. All services invoked during the web request must use the same ISession.  This is a crucial detail.  You may be fetching a domain entity from a repository and passing it later into a domain service which attempts to persist it at a later time.  The domain service will blow up if the entity object is not part of the same ISession within the domain service.
  3. At the end of the request, all outstanding changes to the ISession need to be committed if there were no errors detected during the web request and the ISession should be disposed at the end of every request.

As I hinted at earlier before, we use an interface called ITransactionBoundary to govern the lifecycle of an ISession.  As you can see in the preceding section, StructureMap can only resolve an ISession by going through an ITransactionBoundary object.  The implementation of this stinker is shown below:

    public class NHibernateTransactionBoundary : INHibernateTransactionBoundary

    {

        private readonly ISessionSource _sessionSource;

        private bool _isInitialized;

        private ISession _session;

        private ITransaction _transaction;

 

        public NHibernateTransactionBoundary(ISessionSource sessionSource)

        {

            _sessionSource = sessionSource;

        }

 

        public ISession Session

        {

            get

            {

                ensure_initialized();

                return _session;

            }

        }

 

        public bool IsDisposed { get; private set; }

 

        public void Start()

        {

            _session = _sessionSource.CreateSession();

            _session.FlushMode = FlushMode.Commit;

            _transaction = _session.BeginTransaction();

            _isInitialized = true;

        }

 

        public void Commit()

        {

            should_not_be_disposed();

            ensure_initialized();

            _transaction.Commit();

        }

 

        public void Rollback()

        {

            should_not_be_disposed();

            ensure_initialized();

            _transaction.Rollback();

 

            _transaction = _session.BeginTransaction();

        }

 

        public void Dispose()

        {

            IsDisposed = true;

            if (_transaction != null) _transaction.Dispose();

            if (_session != null) _session.Dispose();

        }

 

        private void should_not_be_disposed()

        {

            if (! IsDisposed) return;

            throw new ObjectDisposedException(“NHibernateTransactionBoundary”);

        }

 

        private void ensure_initialized()

        {

            if (!_isInitialized)

            {

                throw new InvalidOperationException(

                    “An attempt was made to access the database session outside of a transaction. Please make sure all access is made within an initialized transaction boundary.”);

            }

        }

    }

 

We typically don’t have to use ITransactionBoundary directly.  We use a class called TransactionProcessor as a helper to manage the transaction lifecycle.  A little bit of this class is shown below:

        private void execute(Action<IContainer> action)

        {

            IContainer container = null;

            lock (_locker)

            {

                container = _container;

            }

 

            // This is using the new “Nested” Container feature of StructureMap

            // to create an entirely new Container object that is “scoped” to

            // this action

            using (IContainer nestedContainer = container.GetNestedContainer())

            using (var boundary = nestedContainer.GetInstance<ITransactionBoundary>())

            {

                boundary.Start();

                action(nestedContainer);

                boundary.Commit();

            }

        }

I’m not sure how clear it is what is happening above, so let me explain all the steps that are happening here:

  1. TransactionProcessor takes in a reference to the root StructureMap IContainer of the application (IContainer is injected into itself by default).  From the main IContainer, it creates a new “Nested” container that references all the same configuration as the parent container including the same singleton object of our NHibernateSessionSource, but scopes all “Transient” objects to the lifecycle of the new nested container.  What this means is that any object created/resolved by the nested container that asks for an ISession object in either a constructor or setter will get the exact same object instance of ISession.  This way all services invoked in the web request will be using the same identity map and logical unit of work even though they are created separately and independently.  When the nested container is disposed, it will attempt to dispose all of the objects that it created.  This is new behavior in StructureMap I built specifically for NHibernate usage in a web application.
  2. TransactionProcessor pulls a new ITransactionBoundary object out of the nested container and calls Start() which will spin up a new ISession and start a new transaction.  Remembering the rules of nested container behavior I outlined above, you can see that only one ITransactionBoundary is created for the nested container, so only one ISession is used for all other services.
  3. TransactionProcessor uses the “Action<IContainer>” passed into it against the nested container to perform an action within a transaction
  4. TransactionProcessor calls Commit() to finish the transaction and flush changes from the ISession to the database
  5. The using {} block finishes and disposes the TransactionBoundary which internally disposes the ISession.  Technically, you could get by with only the first using block up above.

 

In the past you’ve typically dealt with NHibernate in web applications by scoping the ISession per HttpContext and using HttpModule’s to flush and/or dispose the ISession after the request is finished.  We’re using a combination of the new StructureMap nested container functionality and FubuMVC’s “ActionBehavior” model to manage ISession lifecycle in our application.  All of our routing requests have to go through a top level behavior called TransactionalContainerBehavior that invokes the transaction mechanics around the rest of the web request handling:

    public class TransactionalContainerBehavior : IActionBehavior

    {

        private readonly IContainer _container;

        private readonly ServiceArguments _arguments;

        private readonly Guid _behaviorId;

 

        public TransactionalContainerBehavior(IContainer container, ServiceArguments arguments, Guid behaviorId)

        {

            _container = container;

            _arguments = arguments;

            _behaviorId = behaviorId;

        }

 

        public void Invoke()

        {

            _container.ExecuteInTransaction<IContainer>(c =>

            {

                c.GetInstance<IAuthenticationService>().SetupAuthenticationContext();

 

                invokeRequestedBehavior(c);

            });

        }

 

        private void invokeRequestedBehavior(IContainer c)

        {

            var behavior = c.GetInstance<IActionBehavior>(_arguments.ToExplicitArgs(), _behaviorId.ToString());

            behavior.Invoke();

        }

    }

 

“ExecuteInTransaction<>()” is an extension method on IContainer that we use as a convenience to perform actions within a transactional boundary.  The advantage of the FubuMVC + Nested Container approach that I like is how all the mechanics are here in one spot instead of having to register the HttpModule where you have less control over the ordering of events.

 

Runtime Usage of NHibernate

Okay, assuming that you’re still with me and I haven’t bored the pants off of you, let’s go onto our Repository.  We’re not very strict about DDD, so I’m perfectly content to use a single generic Repository that uses this signature:

    public interface IRepository

    {

        DomainEntity FindByPath(string path);

 

        RESULT ExecuteScalarCommand<RESULT>(string sqlCommandText);

 

        // Find an Entity by its primary key

        // We assume and enforce that every Entity

        // is identified by an “Id” property of

        // type long

        T Find<T>(Guid id) where T : Entity;

 

        // Query for a specific type of Entity

        // with Linq expressions.  More on this later

        IQueryable<T> Query<T>();

        IQueryable<T> Query<T>(Expression<Func<T, bool>> where);

        IQueryable<T> Query<T>(IQueryExpression<T> queryExpression) where T : DomainEntity;

 

        T FindBy<T, U>(Expression<Func<T, U>> expression, U search) where T : class;

        T FindBy<T>(Expression<Func<T, bool>> where);

 

        // Basic operations on an Entity

        void Delete(object target);

        void Save(object target);

        void Insert(object target);

        void RejectChanges(object target);

        T[] GetAll<T>();

    }

 

It’s way, way  beyond the scope of this already long post to discuss the pros and cons of having “tight” repositories that expose specific queries and hide the save/insert/update methods.  For us, this has worked very well.  Even if you’re using a more strict DDD approach to control who and where domain entities can be updated and reuse queries, I think you could back the specific repositories (CustomerRepository, SaleRepository, etc.) with our generic IRepository.  The single biggest reason is because it gives you one simple switch in your IoC tool of choice to switch to:

    public class InMemoryRepository : IRepository

 

that stores objects in memory and uses Linq to Objects for it’s querying to be a high performance in memory standin during automated tests.  This has been hugely advantageous for us.

Most of the methods in our concrete Repository class just delegate straight to the inner ISession object.

We do not use the longhand way of invoking Linq (the whole Yoda speak version of Sql).  Since I think that stuff is completely unreadable, I’m perfectly content to just pass little expressions in for ordering and querying.

 

I won’t get into it unless someone wants it, but we have a simplistic Fluent Interface I named “SmartGrid” that we use to create NHibernate projects with the older ICriteria mechanism in NHibernate.  Here’s an example:

    public class MyCasesGrid : SmartGrid<Case>, IMyCasesQuery

    {

        public MyCasesGrid(ISession session, User user, IUrlRegistry registry, IDisplayFormatter displayFormatter)

            : base(session, registry, displayFormatter)

        {

            // Sorting

            SortAscending(x => x.Created);

 

            // What to show and fetch from the database

            ShowViewLink(x => x.Identifier);

            Show(x => x.Contact.FullName).HeaderFrom(CoreMessageKeys.CONTACT_KEY);

            Show(x => x.Site.Name).OuterJoin().HeaderFrom(CoreMessageKeys.SITE_KEY);

            Show(x => x.Title);

 

            // What data to fetch

            Where(x => x.Owner).IsIs(user)

                .And(x => x.Condition).IsNot(Condition.Closed)

                .And(x => x.Queue).IsNull();

        }

    }

This little FI is doing more than setting up the ICriteria projection.  It’s also configuring how this little “gridlet” is displaying data and even automagically creating a whole new set of routes in the application to handle paging and sorting requests from the UI.

 

Our Workflow

Lastly, I wanted to talk about our workflow and how we go about adding or changing elements in our persistence.  The first think I want to say is that persistence related concerns are a very, very small fraction of our total effort.  I’d even say that database, persistence, or NHibernate related work is no more than 2-3% of our development effort, if that.  Contrast that to about 8-10 years ago when better than half of my time was spent on writing DDL, stored procedures, and ADO manipulation code to pull or push data to and from the database. 

So what do we do?  I typically make the changes I need to our domain model as things come up.  I usually like to wrap up the business logic and even the UI code that interacts with the new entity changes first, then turn to making the new changes persistent.  To add the persistence, we write an integration test that expresses what fields or properties are supposed to be persisted using a modified version of the mapping testing tools in Fluent NHibernate like this (actually, I don’t know if this is still in FNH.  Chad & I wrote it originally for what ended up becoming FNH, but it might have gotten tossed out.  You have to customize it quite a bit per app anyway.  I’ll blog on this too if someone wants it):

        [Test]

        public void Save_and_load_a_Site()

        {

            IList<Address> addressList = new[]

                {

                    new Address { Address1 = “123 Main Street”, City = “Austin”, PostalCode = “78703″},

                    new Address { Address1 = “456 Main Street”, City = “Austin”, PostalCode = “78704″},

                    new Address { Address1 = “789 Main Street”, City = “Austin”, PostalCode = “78705″}

                };

 

            new VerifyTheMappingsOf<Site>(spec => spec

                .CheckProperty(s => s.Identifier, “something”)

                .CheckProperty(s => s.Name, “a”)

                .CheckProperty(s => s.SiteType, “the site type”)

                .CheckProperty(s => s.Phone, “555-555-5555″)

                .CheckProperty(s => s.AlternateName, “altname”)

                .CheckProperty(s => s.Website, “www.foo.com”)

                .CheckProperty(s => s.Status, “Active”)

                .CheckReference(s => s.Calendar, ObjectMother.ValidEmptyWorkCalendar(Guid.NewGuid().ToString()))

                .CheckReference(s=> s.PrimaryAddress, addressList[0])

                .CheckReadOnlyList(s => s.GetAddresses(), addressList, (s, addr) => s.AddAddress(addr), addr => addr.Address1));

        }

The test above creates a new Site object with the suggested property values, saves the new Site object in one ISession and gets the newly assigned Id, then fetches a second copy of the new Site object from an entirely new ISession and checks that each property was successfully persisted.  All this test really does is exercise the NHibernate mappings end to end just to prove that we can successfully persist and load these properties.  After that, we largely assume that NHibernate itself works.  I should say that these tests have helped plenty to weed out minor problems in NHibernate configuration as we add new configuration.

Once I’ve got the new persistence test in place and it happily fails because we haven’t configured anything yet, I add some configuration.  In this case I might add a new ClassMap<Site> class to the core assembly with Fluent NHibernate configuration for the Site class:

    // DomainMap<T> is a Dovetail specific

    // subclass of ClassMap<T> that adds

    // some conventional configuration

    public class SiteMap : DomainMap<Site>

    {

        public SiteMap()

        {

            // Map the simple properties

            Map(s => s.Identifier);

            Map(s => s.Name);

            Map(s => s.AlternateName);

            Map(s => s.Website);

            Map(s => s.Phone);

            Map(s => s.Fax);

            Map(s => s.SiteType);

            Map(s => s.Status);

 

            // The Site object has an Address property called PrimaryAddress

            // The code below sets up the mapping for the reference between

            // Site and the Address class

            HasMany(s => s.GetAddresses())

                .Access.AsCamelCaseField(Prefix.Underscore)

                .Cascade.All();

            References(s => s.PrimaryAddress).Cascade.All();

            References(s => s.SupportSite).Cascade.All();

            References(s => s.Calendar).Cascade.All();

 

            HasManyToMany(x => x.GetContracts())

                .LazyLoad()

                .Access.AsCamelCaseField(Prefix.Underscore).Inverse()

                .Cascade.All();

        }

 

    }

Now I’ve got a mapping configured, but no database changes yet.  Easy money, I just run rake target we have called “generate_all” that compiles the code and rebuilds the database from scratch using NHibernate’s hbm2ddl tool to generate the DDL from the mappings (plus adds some baseline data so the application can actually run).  We use a lot of conventions to further enrich the NHibernate mappings to add metadata used to generate the DDL.  The DDL comes out following our naming conventions for tables, primary keys, foreign keys, and builds columns based on the validation attributes decorating our classes for some Ruby on Rails style DRY-ness.

The entire cycle goes pretty fast.  Of course, we’ll have to do something more sophisticated like adopt a migrations tool when we go live and have to maintain backwards compatibility with the database schema, but for now, this approach is happily speeding us along.  All that time that we spent on painstaking data access coding in the early part of this decade gets put into better testing and leaves time for a vastly better user experience.

 

 

 

As Forrest Gump said, that’s all I’ve got to say about that.  I’ll try to jump on questions because it’s an absurd amount of information and code to dump on you.  But maybe now Weston will stop trying to guilt me into writing this post;-)

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Database and Persistence, DI, FubuMVC, IOC, StructureMap. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/members/sdrk/default.aspx sdrk

    Jeremy,

    you mention that we can create several object graphs with service location calls to the nested container and any subsequent method calls to any of these services will be scoped (use the same ISession etc. )

    However consider the following code from one of your other posts:-

    var transaction = ObjectFactory.GetInstance();
    transaction.Execute(x => x.ClearData());

    In this case, DataDriver and its object dependencies will be constructed using a new nested container and all the code inside ClearData will be scoped.

    How can i use the TransactionProcessor to create instances of multiple services like DataDriver and say DataConsumer and invoke some methods on them within the same transaction boundary.

    I know i can do that using – using blocks of nested container/ transaction boundary directly and create instances of all the services i need and invoking methods on them. (but this will result in lot of redundant code

    But how to achieve the same using transactionprocessor ?

    Thanks.

    Nested Container Rocks !!

  • http://codebetter.com/members/sdrk/default.aspx sdrk

    Jeremy,

    you mention that we can create several object graphs with service location calls to the nested container and any subsequent method calls to any of these services will be scoped (use the same ISession etc. )

    However consider the following code from one of your other posts:-

    var transaction = ObjectFactory.GetInstance();
    transaction.Execute(x => x.ClearData());

    In this case, DataDriver and its object dependencies will be constructed using a new nested container and all the code inside ClearData will be scoped.

    How can i use the TransactionProcessor to create instances of multiple services like DataDriver and say DataConsumer and invoke some methods on them within the same transaction boundary.

    I know i can do that using – using blocks of nested container/ transaction boundary directly and create instances of all the services i need and invoking methods on them. (but this will result in lot of redundant code

    But how to achieve the same using transactionprocessor ?

    Thanks.

    Nested Container Rocks !!

  • http://codebetter.com/members/jmiller/default.aspx Jeremy D. Miller

    @Mike,

    TransactionProcessor.Execute() happens inside a FubuMVC behavior and wraps the rest of the pipeline. There isn’t an exact analogue in MSMVC.

  • http://www.mikehenry.name/ Mike Henry

    Thanks for the article. When and how does TransactionProcessor.Execute() get called (and thus make use of the nested container and transaction boundary)?

  • http://fknet.wordpress.com Frantisek

    Jeremy, coool blog entry. I like the idea with workflow: NHibernate integration tests, fluent NHibernate, “generate_all”.

    If you would have a time, could you write a blog about it, please ;o)?

  • http://elegantcode.com Ryan Kelley

    Jeremy, How are you guys wrapping all the transaction stuff to do your Persistence Testing? I keep getting errors about the transaction not being started.

  • http://sm-art.biz ulu

    Has anybody ever had problems with multiple AppDomains per Web site? I don’t know about IIS7, but this thing happened to me while I was using IIS6. Suddenly I had several instances of my singleton, and it was acting weird!

    Shouldn’t be a problem with SessionFactory, but you should be aware of this.

  • http://codebetter.com/members/jmiller/default.aspx Jeremy D. Miller

    @J,

    If you hadn’t already initialized the transaction before requesting the ISession, yes it would throw an exception. That’s a purposeful defensive coding check we did because we retrofitted this stuff in late in the game and it forced us to make the session mgmt correct.

    That’s the part I wouldn’t particularly recommend. You might call this “what we did” and definitely not “what I think you should do.”

  • J

    Hi great post! Will consider it next time i write a webbapp!
    Wouldnt return transaction.Session in CoreRegistry / setupNHibernate() caus an exception because of the ensure_initialized in NHibernateTransactionBoundary?

  • Chris

    Never mind, figured it out from another post!

  • Chris

    I’m currently setting up a new FuBuMvc project using a similar approach.

    Any chance you could post the ExecuteInTransaction extension method?

  • http://blog.coreycoogan.com Corey Coogan

    What a tremendous help Jeremy. Thanks alot.

    corey

  • http://codebetter.com/members/jmiller/default.aspx Jeremy D. Miller

    @Corey,

    public interface ITransactionProcessor
    {
    void Execute(Action action);
    RETURN Execute
    (Func func);
    void Execute
    (Action action);
    void Execute
    (string instanceName, Action action);
    }

    public class TransactionProcessor : ITransactionProcessor
    {
    private readonly object _locker = new object();
    private IContainer _container;

    public TransactionProcessor(IContainer container)
    {
    _container = container;
    }

    public IContainer Container
    {
    get { return _container; }
    set
    {
    lock (_locker)
    {
    _container = value;
    }
    }
    }

    #region ITransactionProcessor Members

    public void Execute(Action action)
    {
    execute(c =>
    {
    var service = c.GetInstance
    ();
    action(service);
    });
    }

    public RETURN Execute(Func func)
    {
    RETURN result = default(RETURN);
    execute(c =>
    {
    var service = c.GetInstance
    ();
    result = func(service);
    });
    return result;
    }

    public void Execute(Action action)
    {
    execute(c =>
    {
    var service = c.GetInstance
    ();
    action(service, c);
    });
    }

    public void Execute(string instanceName, Action action)
    {
    execute(c =>
    {
    var service = c.GetInstance
    (instanceName);
    action(service);
    });
    }

    #endregion

    private void execute(Action action)
    {
    IContainer container = null;
    lock (_locker)
    {
    container = _container;
    }

    using (IContainer nestedContainer = container.GetNestedContainer())
    using (var boundary = nestedContainer.GetInstance())
    {
    boundary.Start();
    action(nestedContainer);
    boundary.Commit();
    }
    }
    }

  • http://blog.coreycoogan.com Corey Coogan

    Hey Jeremy,
    I’m trying to sort some of this stuff for an NH pilot and think your ITransactionBoundary and ITransactionProcessor fit the bill.

    Any chance you could post all the code for the TransactionProcessor?

  • http://codebetter.com/members/jmiller/default.aspx Jeremy D. Miller

    @Dirk,

    The “main” StructureMap container held by the ObjectFactory class is a singleton. The StructureMap container itself manages the lifecycle of everything else.

  • Dirk

    @Chad

    Yes thats right I am not using Structuremap yet, its on my list though I promise :D

    Presumably you would still need to cache StructureMap? Sorry about the caching questions!!

  • http://chadmyers.lostechies.com Chad Myers

    @Dirk:

    Why not just mark it as Singleton and let StructureMap deal with the lifecycle issues?

    Or are you not using StructureMap?

  • Dirk

    @Chad

    No I get what a singleton is and why you would need it here, I was just wondering how you actually store it. e.g. Application cache.

    The thing is I think I have been doing this wrong and creating a sessionfactory per request, which gets the job done but in light of this thread is not the best way to be doing things. So I just wanted to know where I should be storing it, with the Application cache seeming a good choice.

    Thanks again for the reply.

  • http://chadmyers.lostechies.com Chad Myers

    @Dirk:

    It’s a singleton instance. StructureMap’s container has a reference to it.

    It seems like you may not understand what a “Singleton” is. You should read up on this pattern a little as it will help you understand what’s going on here.

  • Dirk

    Thanks for the reply Chad.

    So would you mind telling me where or how it is stored?

    Thanks

  • http://chadmyers.lostechies.com Chad Myers

    @Dirk:

    No, it’s a singleton for the entire app domain. It’s created the first time someone requests it (in our case, in Application_Start) and survives for the rest of the application.

  • Dirk

    So when the web request first comes in a singleton instance of
    SessionFactory is created for that web request, is this then cached for
    subsequent requests?

    So the question is do you cache the SessionFactory?

  • http://blog.coreycoogan.com corey coogan

    Great article Jeremy. I really enjoy the detail you put into these.

    I, personally, would very much like to see more of the SmartGrid. I’m not a bug UI guy and anything that makes that easier is always great to learn.

  • http://joshuaflanagan.lostechies.com Joshua Flanagan

    At the end of the Bootstrapping Nhibernate section above, Jeremy mention that StructureMap knows how to build the DatabaseSettings class from app.config. If you are curious how that works, I wrote it up at:
    http://www.lostechies.com/blogs/joshuaflanagan/archive/2009/07/12/how-we-handle-application-configuration.aspx

  • http://codebetter.com/members/mob/default.aspx Mike O’Brien

    Thanks for your hard work Jeremy. ConnectImplementationsToTypesClosing rocks!

    m

  • http://flux88.com Ben Scheirman

    Thanks for writing this. I always enjoy seeing how other folks utilize NHibernate.