Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using Multiple NHibernate Assemblies with NHSessionManager

0.00/5 (No votes)
1 Feb 2007 4  
This article describes how NHSessionManager can be configured to use multiple NHibernate assemblies

Introduction

In a previous article NHibernate Best Practices with ASP.NET, Generics and Unit Tests by Bill McCafferty, NHSessionManager is configured via App/Web config simply to work with NHibernate core assembly. Since NHSessionManager and other assemblies (Core, Data and Test) are located in the same solution, this simple way is enough for all practical purposes. But for the sake of code reuse, we can think of reorganising the NHibernate utility classes (NHSessionManager, DomainObject, NHGenericDao) and interfaces (IGenericDao) in a separate solution/project. When this is the case, we need a more generic way to specify NHSessionManager configuration.

Another article Using NHibernate with Multiple Databases again by Bill McCafferty is a very good example of how to extend the configuration system of .NET.

Extending Configuration System

We need a configuration section handler and configuration element specification in order to specify multiple NHibernate assemblies via App/Web config.

Our goal is to handle a configuration section like this one:

  <configSections>
    <section name="nhibernate" 
	type="System.Configuration.NameValueSectionHandler, 
	System, Version=1.0.1.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,
	log4net, Version=1.2.9.0, Culture=neutral, PublicKeyToken=b32731d11ce58905"/>
    <section name="castle" 
	type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, 
	Castle.Windsor"/>
    <section name="nHibernateAssemblies" 
	type=" NHibernateSample.Common.Configuration.NHAssembliesSection, 
	NHibernateSample.Common"/>
  </configSections>
  
  <nHibernateAssemblies>
    <NhAssemblies>
      <clearAssemblies />
      <NhAssembly name="Core assembly 1" assembly="ProjectName1.Core"/>
      <NhAssembly name="Another core assembly" assembly="ProjectName2.Core"/>
    </NhAssemblies>
  </nHibernateAssemblies>

NHAssemblyElement

NHAssemblyElement is inherited from ConfigurationElement placed in System.Configuration namespace.

The NHAssemblyElement class has two properties:

  • Name for holding descriptive name for the core assembly
  • Assembly for holding name of the assembly we want NHSessionManager to load
public class NHAssemblyElement : ConfigurationElement
{
  public NHAssemblyElement( )
  {

  }

  public NHAssemblyElement( string name, string assembly )
  {
    Name = name;
    Assembly = assembly;
  }

  [ConfigurationProperty("name", IsRequired = true, IsKey = true, 
	DefaultValue = "Not Supplied")]
  public string Name
  {
    get { return (string)this["name"]; }
    set { this["name"] = value; }
  }

  [ConfigurationProperty("assembly", IsRequired = true, DefaultValue = "Not Supplied")]
  public string Assembly
  {
    get { return (string)this["assembly"]; }
    set { this["assembly"] = value; }
  }
}

NHAssembliesCollection

NHAssembliesCollection is inherited from the standard ConfigurationElementCollection class.

[ConfigurationCollection(typeof(NHAssemblyElement))]
public class NHAssembliesCollection : ConfigurationElementCollection
{
  public NHAssembliesCollection( )
  {
    NHAssemblyElement element = (NHAssemblyElement)CreateNewElement();
    Add(element);
  }

  public override ConfigurationElementCollectionType CollectionType
  {
    get
    {
      return ConfigurationElementCollectionType.AddRemoveClearMap;
    }
  }

  protected override ConfigurationElement CreateNewElement( )
  {
    return new NHAssemblyElement();
  }

  protected override object GetElementKey( ConfigurationElement element )
  {
    return ((NHAssemblyElement)element).Name;
  }

  public NHAssemblyElement this[int index]
  {
    get
    {
      return (NHAssemblyElement)BaseGet(index);
    }
    set
    {
      if (BaseGet(index) != null)
      {
        BaseRemoveAt(index);
      }

      BaseAdd(index, value);
    }
  }

  new public NHAssemblyElement this[string name]
  {
    get
    {
      return (NHAssemblyElement)BaseGet(name);
    }
  }

  public int IndexOf( NHAssemblyElement assembly )
  {
    return BaseIndexOf(assembly);
  }

  public void Add( NHAssemblyElement assembly )
  {
    BaseAdd(assembly);
  }

  protected override void BaseAdd( ConfigurationElement element )
  {
    BaseAdd(element, false);
  }

  public void Remove( NHAssemblyElement assembly )
  {
    if (BaseIndexOf(assembly) >= 0)
    {
      BaseRemove(assembly.Name);
    }
  }

  public void RemoveAt( int index )
  {
    BaseRemoveAt(index);
  }

  public void Remove( string name )
  {
    BaseRemove(name);
  }

  public void Clear( )
  {
    BaseClear();
  }
}

NHAssembliesSection

NHAssembliesSection inherits from the standard ConfigurationSection and implements the section handler specified in the configuration file as:

<section name="nHibernateAssemblies" 
	type=" NHibernateSample.Common.Configuration.NHAssembliesSection, 
	NHibernateSample.Common"/>

The code is as follows: 

public class NHAssembliesSection : ConfigurationSection
{
  [ConfigurationProperty("NhAssemblies", IsDefaultCollection = false)]
  [ConfigurationCollection(typeof(NHAssembliesCollection), 
	AddItemName = "NhAssembly", ClearItemsName = "clearAssemblies")]
  public NHAssembliesCollection NHAssemblies
  {
   get
   {
    NHAssembliesCollection assembliesCollection = 
	(NHAssembliesCollection)base["NhAssemblies"];
    return assembliesCollection;
   }
  }
}

Little Modification to NHSessionManager

In NHSessionManager, we have to change the InitSessionFactory() method a little bit.

The original version provided by Bill McCafferty implements loading of NHibernate assemblies with the following code:

private void InitSessionFactory() 
{
 NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
 // The following makes sure the web.config contains 
 // a declaration for the HBM_ASSEMBLY appSetting
 if (ConfigurationManager.AppSettings["HBM_ASSEMBLY"] == null || 
     ConfigurationManager.AppSettings["HBM_ASSEMBLY"] == "") 
 {
  throw new ConfigurationErrorsException
	("NHibernateManager.InitSessionFactory: \"HBM_ASSEMBLY\" must be " +
    "provided as an appSetting within your config file. \"HBM_ASSEMBLY\" 
	informs NHibernate which assembly " +
    "contains the HBM files. It is assumed that the HBM files are embedded resources. 
	An example config " +
    "declaration is \" key="\" />");
 }
 
 cfg.AddAssembly(System.Configuration.ConfigurationManager.AppSettings["HBM_ASSEMBLY"]);
 sessionFactory = cfg.BuildSessionFactory();
}

The code above handles a configuration file as the following one:

<appSettings>
 <add key="HBM_ASSEMBLY" value="NHibernateSample.Core"/>
</appSettings>

As I mentioned in the introduction of the article, with this NHSessionManager implementation we have to change NHSessionManager source code and recompile every time we want to handle another NHibernate assembly.

Our alternative InitSessionFactory implementation of NHSessionManager code looks like the following:

private void InitSessionFactory( )
{
  NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();

  NHAssembliesSection nhAssembliesSection = 
	ConfigurationManager.GetSection("nHibernateAssemblies") as NHAssembliesSection;
  
  if(nhAssembliesSection == null)
  {
    throw new ConfigurationErrorsException
	("nHibernateAssemblies section not defined in application configuration!");
  }

  foreach(NHAssemblyElement element in nhAssembliesSection.NHAssemblies)
  {
    try
    {
      cfg.AddAssembly(element.Assembly);
    }
    catch (Exception e)
    {
      throw new Exception(" Can not add assembly! " + e.Message, e.InnerException);
    }
  }

  try
  {
    sessionFactory = cfg.BuildSessionFactory();
  }
  catch (Exception e)
  {
    throw new Exception(" Can not create session factory! " + 
	e.Message, e.InnerException);
  }
}

History

  • 1st February, 2007: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here