Web Api 2, Oracle and Entity Framework

I spent about two days trying to figure out how to expose the Oracle.ManagedDataAccess 4.121.1.0 library over a Web Api 2.2 OData v4 Endpoint. Looking through the Oracle documentation, Oracle Managed Data Access doesn’t currently support Entity Framework v6, so you have to use Entity Framework v5. DevArt supplies a Entity Framework 6 compatible product, unfortunately I didn’t have the time to get budget for this simple proof of concept and I haven’t had much luck with trial periods as they never seem to be active when I need them. When Oracle releases the ODP.NET 12c r3 libraries later summer 2014, this post will be deprecated as it comes with EF 6 support.

First thing is to install Entity Framework via NuGet Package Manager

Install-Package EntityFramework -Version 5.0.0

Next you need to install WebApi v2.2 with OData support.

Install-Package Microsoft.AspNet.OData

Finally you need to install the Oracle.ManagedDataAccess library, which is called ODP.NET.

Install-Package odp.net.managed

Now that all of the packages are installed, the oracle connection strings need to be setup. I had issues connecting to oracle 11g with the default “Data Source = xyz; user id= myuser; password = abcd123” connection string. I received an error:

ORA-12154: TNS:could not resolve the connect identifier specified

Doing some research, you get this error when Oracle can not find the list of registered oracle servers on your network. I remember Sql Server having a discovery protocol similar to this, but I guess that the port numbers are not consistent the way they are in the Microsoft world so you have to go and specify the direct network location in the connection string.

Documentation stated that you should be able to install ODP.NET and point to the TnsNames.ora file to get the connection information. The TnsNames.ora file looks to be configured after the install, so I guess I got lucky there. Consulting with your Oracle DBA may help you locate the information for your server. This stackoverflow post gave me the connection string structure based on the ora file. You can’t just copy the values directly in there, you have to remove the Alias.

I wanted to configure the connection string in my web.config file instead of specifying it directly. To do that, you need the Oracle.ManagedDataAccess.Client.OracleClientFactory provider to be specified in the providerName field of the configuration file.


<connectionStrings>
<add name="myConnectionString" connectionString="from stackoverflow article" providerName = "Oracle.ManagedDataAccess.Client"/>

Adding this I received an error “Failed to find or load the registered .Net Framework Data Provider.”. This error occurs when the Oracle.ManagedDataAccess.Client.OracleClientFactory class isn’t registered in the web.config or machine.config. I don’t like putting assemblies in the GAC on production servers, so I’m glad this showed up on my workstation and not later in the release cycle. Adding the following to the configuration file resolved the error:


<system.data>
<DbProviderFactories>
<add name="Oracle ManagedDataAccess Provider"
invariant="Oracle.ManagedDataAccess.Client"
description=".Net Framework Data Provider for Oracle"
type="Oracle.ManagedDataAccess.Client.OracleClientFactory, Oracle.ManagedDataAccess" />
</DbProviderFactories>
</system.data>

With Entity Framework working, its time to focus on WebApi. Following any number of tutorials on the subject can get you stated, I used this one.

I made a few tweaks adding ODataRoutePrefixAttribute to my controller and ODataRoute to my action, but otherwise it is the same.

Visualize the TPL Dataflow Predefined Blocks as Pixel Art

I’ve been messing around with the TPL Dataflow and found I was visualizing the block types when reading the descriptions here http://msdn.microsoft.com/en-us/library/hh228603(v=vs.110).aspx

I did a quick sketch up using simple pixel art. 

 Image 

In order we have 

Buffer Blocks

  • BufferBlock
  • BroadcastBlock
  • WriteOnceBlock

Execution Blocks

  • ActionBlock
  • TransformBlock
  • TransformManyBlock

Grouping Blocks

  • BatchBlock
  • JoinBlock
  • BatchedJoinBlock

Visualization helps me when learning new concepts, so hopefully this helps others who are having trouble picking a block for a dataflow.

 

ASP.NET User Principal assignment to thread.

I’ve been digging into our legacy codebase that does custom identity management and ran into a question I had trouble answering.

Q: Does ASP.NET assign a user to the thread on every request?
A: Yes.

I did a simple demo using the MVC3 template with a fake membership provider.

In Global.asax.cs

private void LogUserState(string method, object sender, EventArgs e)
{
	var application = sender as HttpApplication;
	if (application == null)
		return;

	if (application.User == null || application.User.Identity == null)
		Trace.WriteLine(string.Format("{0}: Current User is Missing. Thread ID {1}", method, Thread.CurrentThread.ManagedThreadId));
	else
		Trace.WriteLine(string.Format("{0}: Current User is {1}. Thread ID {2}", method, application.User.Identity.Name, Thread.CurrentThread.ManagedThreadId));
}

protected void Application_BeginRequest(object sender, EventArgs e)
{
	LogUserState(MethodInfo.GetCurrentMethod().Name, sender, e);
}

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
	LogUserState(MethodInfo.GetCurrentMethod().Name, sender, e);
}

protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
	LogUserState(MethodInfo.GetCurrentMethod().Name, sender, e);
}

Output is as follows

Application_BeginRequest: Current User is Missing. Thread ID 38
Application_AuthenticateRequest: Current User is abc123. Thread ID 38
Application_PostAuthenticateRequest: Current User is abc123. Thread ID 38

Razor View Error Sitecore.Mvc.AssemblyInitializer in Area project Sitecore 6.6 Technical Preview

Using Sitecore 6.6 technical preview I get the following error in the Razor view engine and its breaking my intellisense.

ASP.NET runtime error: The pre-application start initialization method InitializeAssembly on type Sitecore.Mvc.AssemblyInitializer threw an exception with the following error message: Could not read Sitecore configuration..

Our project uses heavy customization and MVC Areas to allow for a plugin type architecture. We have area projects that contain the MVC assets and views for the plugin and the intellisense was broken in one of those projects. It appears that the Sitecore.Mvc.AssemblyInitializer method is a bootstrapped method that runs during the Razor parsing of the view file in order to build the references necessary to show the intellisense.

A simplified example, where intellisense is broken in the PluginProject:

  • Solution
    • PluginProject
      • Web.config
    • SiteProject
      • App_Config
        • Include
          • Event.config
        • ConnectionStrings.config
      • Web.config

I originally thought the issue was due to an MVC 4 installation, but removing the install did nothing to fix the issue. Turns out the error message (as usual) is the key. The Sitecore.Mvc.AssemblyInitializer method is looking for the sitecore configuration in the area project web.config, which it can’t find in the portable area project because the configuration is in the main web.config of the site project.

Since we only require a reference to the Sitecore.Mvc.dll and not for that dll to be in the area project bin directory, I deleted the file and set the reference to “copy local = false”. The bootstrapper for Razor now doesn’t see the Sitecore.Mvc.dll in the bin directory and the error goes away.

Running Sitecore Agents with Sitecore Powershell Console

We recently needed to execute the Sitecore agent for cleaning the event queue because it wasn’t running on its own.

We are using Sitecore 6.6

First of all, install Powershell for Sitecore. http://marketplace.sitecore.net/en/Modules/Sitecore_PowerShell_console.aspx

Once that is installed, go into sitecore and start the PowerShell console.

In the powershell console, type:

PS master:\> $cleanupEventQueue = new-object Sitecore.Tasks.CleanupEventQueuentQueue
PS master:\> $cleanupEventQueue.DaysToKeep = 1
PS master:\> $cleanupEventQueue.Run()

This will run the code for the task to cleanup the queue. There are other tasks defined in the agent section of the configuration that can be run the same way. For example, we also run the CleanPublishQueue keeping 30 days.

PS master:\> $cleanupPublishQueue = new-object Sitecore.Tasks.CleanupPublishQueue
PS master:\> $cleanupPublishQueue.DaysToKeep=30
PS master:\> $cleanupPublishQueue.Run()

Unit Testing Sitecore MVC with Glass Mapper

I work on a large Sitecore 6.6 MVC project and we have been spending a lot of time thinking about Unit Testing with Sitecore.

The big issue, for anyone familiar with Unit Testing MVC, is that static contexts make unit testing difficult. Traditional Sitecore development involves heavy use of the static ‘Sitecore.Context’ to perform almost every operation. Static Context doesn’t change much in Sitecore’s MVC extension, with the use of PageContext and Rendering Context to fetch where you are in the site, and Sitecore.Context to perform queries.

Some have tried to solve this problem by creating a Sitecore Service concept and mocking out the Item and Field classes with an adapter pattern. The one issue we faced was that we still had lots of mapping between these interfaces and our POCO objects that represented the models.

We looked around at various blog posts and even had a conversation with Sitecore about the topic. The general consensus was that Glass Sitecore Mapper makes Unit Testing easier, but we noticed a recurring pattern in our development.

public class PromotionsController : Controller
{
   public ActionResult Index()
   {
       // resolve the Glass Sitecore Service
       // this could also be done by resolving as a controller dependency
       ISitecoreService sitecoreService = DependencyResolver.Current.GetService<ISitecoreService>();

       // this is the failover id which is the default
       Guid dataSource = Constants.SitecoreTree.Content.Sites.Global.Data.Demos.DataSource;

       // rendering context shouldn't be null if we are using a rendering
       if(RenderingContext.CurrentOrNull != null
          && RenderingContext.Current.Rendering != null
          && RenderingContext.Current.Rendering.Item != null)
       {
           dataSource = RenderingContext.Current.Rendering.Item.ID.Guid;
       }

       // fetch the demo model from the Sitecore service
       Promotion promotionModel = sitecoreService.GetItem<Promotion>(dataSource);
       return View(promotionModel);
   }
}

Our model would look something like this


[SitecoreClass]
public class Promotion
{
    [SitecoreId]
    public virtual Guid Id { get; set; }

    [SitecoreField("Promotions")]
    public virtual IEnumerable<PromotionItem> Items { get; set; }
}

[SitecoreClass]
public class PromotionItem
{
    [SitecoreId]
    public virtual Guid Id { get; set; }

    [SitecoreField]
    public virtual string Title { get; set; }

    [SitecoreField]
    public virtual string Description { get; set; }

    [SitecoreField]
    public virtual Glass.Sitecore.Mapper.FieldTypes.Image Image { get; set; }

    [SitecoreField]
    public virtual Glass.Sitecore.Mapper.FieldTypes.Link Action { get; set; }
}

Looking at the above code, we see that we are doing the same operations over and over

  1. Resolve ISitecoreService
  2. Set Default Item ID
  3. If RenderingContext is Present, override Default Item ID
  4. Use datasource to fetch item using ISitecoreService
  5. Return to View

MVC provides many extension points to plug-in common code. For this particular set of logic, we decided to use a Model Binder. The Model Binder syntax can be a bit verbose using the default values, we wanted something that was concise and described what we were using to accomplish model binding. This resulted in the ‘GlassAttribute’.

public class GlassAttribute
    : CustomModelBinderAttribute, IModelBinder
{
    public string DataSource { get; set; }

    public GlassDataSourceBehavior Behavior { get; set; }

    public override IModelBinder GetBinder()
    {
        return this;
    }

    public virtual object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // get the model type
        var modelType = bindingContext.ModelType;

        // get the sitecore service
        ISitecoreService sitecoreService = DependencyResolver.Current.GetService();
        if (sitecoreService == null)
                throw new Exception("Unable to resolve dependency for Glass.Sitecore.Mapper.ISitecoreService. Register the interface once in the global application, or in the AreaRegistration.");

        Guid dataSourceId = Guid.Empty;
        string dataSourcePath = string.Empty;

        // check if its an ID or path
        if (!Guid.TryParse(DataSource, out dataSourceId))
            dataSourcePath = DataSource;

        // do some workflow
        if (Behavior == GlassDataSourceBehavior.Failover)
        {
            // get the current rendering context id
            // uses monads http://nuget.org/packages/Monads
            var currentId = RenderingContext.CurrentOrNull
                .With(x => x.Rendering)
                .With(x => x.Item)
                .With(x => x.ID)
                .Return(x => x.Guid, Guid.Empty);

            // if the current id is not null, use it for the datasource
            if (currentId != Guid.Empty)
                dataSourceId = currentId;
        }

        // do we have an id?
        if (dataSourceId != Guid.Empty)
            return sitecoreService.GetItem(modelType, dataSourceId);

        // do we have a path?
        if (!string.IsNullOrWhiteSpace(dataSourcePath))
            return sitecoreService.GetItem(modelType, dataSourcePath);

        // no item found to bind
        return null;
    }
}

And the data source behavior

public enum GlassDataSourceBehavior
{
    Failover,
    Override
}

We also need to extend the ISitecoreService to use System.Type instead of generics.


public static class ISitecoreServiceExtensions
{
    public static object GetItem(this ISitecoreService service, Type type, string path)
    {
        MethodInfo getItemMethod = typeof(ISitecoreService).GetMethod("GetItem", new Type[] { typeof(string) }, null);
        MethodInfo genericGetItemMethod = getItemMethod.MakeGenericMethod(type);

        return genericGetItemMethod.Invoke(service, new object[] { path });
    }

    public static object GetItem(this ISitecoreService service, Type type, Guid id)
    {
        MethodInfo getItemMethod = typeof(ISitecoreService).GetMethod("GetItem", new Type[] { typeof(Guid) }, null);
        MethodInfo genericGetItemMethod = getItemMethod.MakeGenericMethod(type);

        return genericGetItemMethod.Invoke(service, new object[] { id });
    }
}

Here is a example of use.

public ActionResult Index([Glass]Promotion promotionModel)
{
    return View(promotionModel);
}

Most use cases will just contain the [Glass] attribute, but we added a failover for cases when the rendering datasource isn’t set in Sitecore. The logic in the glass attribute may need some tweaking in the Failover scenario. The RenderingContext.CurrentOrNull.Rendering.Item automatically fails over to the PageContext so we have had a discussion about adding a Behavior for using the user specified datasource when the Rendering is missing a datasource in case the user wants to catch binding before the PageContext is used.

A failover scenario would look like the following


// DataSource constant should now be a string
public ActionResult Index([Glass(
   DataSource=Constants.SitecoreTree.Content.Sites.Global.Data.Demos.DataSource)]Promotion promotionModel)
{
    return View(promotionModel);
}

An override scenario would look like the following

// DataSource constant should now be a string
public ActionResult Index([Glass(
DataSource=Constants.SitecoreTree.Content.Sites.Global.Data.Demos.DataSource,
Behavior=GlassDataSourceBehavior.Override]Promotion promotionModel)
{
    return View(promotionModel);
}

We now have a controller action that is capable of being unit tested. Depending on how deep you go with unit tests, you could write a unit test for the GlassAttribute as well.

Load Complex Object Graph in NHibernate 3.2 with LINQ provider and Futures

I recently had a problem at work that required a deep object graph load of report metadata from the database. Looking around I found a couple posts from Oren Eini (Ayende) that used multi select and
hql.

I tried using the multi select and ran into this issue due to the composite ids in my application. The solution is to deal with the bug or refactor your database schema. I guess using unique constraint would be a solution to this issue, unfortunately I would have a tough time selling that option.

That brings me to the HQL, which ends up working, but I have personal issues with using Magic Strings and I would really like to use the LINQ provider. I looked around and couldn’t find any examples using the provider, so after much tinkering here is my solution.

The object model:

public class ReportServerReport
{
    public virtual Guid Id { get; set; }
    public virtual string Name{get;set;}
    public virtual IList<ReportServerReportVersion> Versions{ get; set; }
}

public class ReportServerReportVersion
{
    public virtual int Id { get; set; }
    public virtual ReportServerReport Report{get;set;}
    public virtual IList<ReportServerReportVersionExport> Exports { get; set; }
    public virtual IList<ReportServerReportVersionParameter> Parameters { get; set; }
}

public class ReportServerReportVersionExport
{
    public virtual int Id { get; set; }
    public virtual ReportServerReportVersion Version { get; set; }
}

public class ReportServerReportVersionParameter
{
    // name and report version form a composite key
    public virtual string Name { get; set; }
    public virtual ReportServerReportVersion Version { get; set; }

    public virtual IList<ReportServerReportVersionParameterDefaultValue> DefaultValues { get; set; }
    public virtual IList<ReportServerReportVersionParameterValidValue> ValidValues { get; set; }
}

public class ReportServerReportVersionParameterDefaultValue
{
    // Parameter and Sequence form a composite id
    public virtual ReportServerReportVersionParameter Parameter { get; set; }
    public virtual int Sequence { get; set; }

    public virtual string Value { get; set; }
}

public class ReportServerReportVersionParameterValidValue
{
    /// Parameter and Sequence for a composite id
    public virtual ReportServerReportVersionParameter Parameter { get; set; }
    public virtual int Sequence { get; set; }

    public virtual string Value { get; set; }
    public virtual string Label { get; set; }
}

The mapping is pretty straight forward, I won’t list it here but I have noted in the code above where the composite Id’s live. I’m using FlunetNHibernate and the CompositeId() function with KeyReference() and KeyProperty()

/// <summary>
/// Returns the ReportServerReportVersion by name and all metadata
/// </summary>
/// <param name="names">the name list of report names </param>
/// <returns></returns>
public IEnumerable<ReportServerReportVersion> GetReportServerReportVersionByName(params string[] names)
{
      // used for shorthand
      var s = Model.Session;

      // get the list of version ids
      // we want to execute this immediately
      var idList =
          s.Query<ReportServerReportVersion>()
           .Where(x => x.Active
                   && x.StartDate <= DateTime.Now
                   && x.EndDate >= DateTime.Now
                   && names.Contains(x.ReportServerReport.Name))
           .Select(x=>x.Id)
           .ToList();

     // create one query per path
     var versionList =
          s.Query<ReportServerReportVersion>()
           .Where(x => idList.Contains(x.Id))
           .Fetch(x => x.ReportServerReport)
           .ToFuture();

    // results don't matter here, we are using these guys to
    // force NHibernate to pull back data for the proxies
    s.Query<ReportServerReportVersion>()
     .Where(x => idList.Contains(x.Id))
     .FetchMany(x => x.Exports)
     .ToFuture();

    s.Query<ReportServerReportVersion>()
     .Where(x => idList.Contains(x.Id))
     .FetchMany(x => x.Parameters)
     .ToFuture();

    s.Query<ReportServerReportVersionParameter>()
     .Where(x => idList.Contains(x.ReportServerReportVersion.Id))
     .FetchMany(x=>x.ValidValues)
     .ToFuture();

    s.Query<ReportServerReportVersionParameter>()
     .Where(x => idList.Contains(x.ReportServerReportVersion.Id))
     .FetchMany(x => x.DefaultValues)
     .ToFuture();

    return versionList;
}

Change ConnectionString NHibernate

At work, we scale our databases based on a multi-database, same schema deployment. So each of our customers has a single environment for all of their data. This keeps customer data isolated, but causes a pain for NHibernate when attempting to switch dynamically between customer databases in a WCF service oriented scenario. The big issue is the startup time associated with building a ISessionFactory instance for each and every customer database.

In WCF we don’t know which connection string we should use until after impersonation has kicked in. We can’t cache all potential session factories in the global.asax.cs because it would take forever (100+ customers). Loading the ISessionFactory after we know the impersonated user isn’t an option either because the initial start up time is in the neighborhood of 8 seconds (we have a lot of entities).

My first attempt at changing the connection string at runtime was to pass an IDbConnection to ISessionFactory.OpenSession(IDbConnection). After looking through the NHibernate source, I discovered a comment on the ISessionFactory interface

/// <summary> 
/// Open a ISession on the given connection
/// </summary>
/// A connection provided by the application
/// A session
///
/// Note that the second-level cache will be disabled if you
/// supply a ADO.NET connection. NHibernate will not be able to track
/// any statements you might have executed in the same transaction.
/// Consider implementing your own .
///
ISession OpenSession(IDbConnection conn);

Ok, the comment says second level cache will be disabled for tracking statements in the same transaction. What this means in reality is you get one of these nasty errors when trying to call ISession.Save(object obj) from within a transaction.

Type : System.NullReferenceException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Message : Object reference not set to an instance of an object.
Source : NHibernate
Help link :
Data : System.Collections.ListDictionaryInternal
TargetSite : Void CloseConnection(System.Data.IDbConnection)
Stack Trace :    at NHibernate.Connection.ConnectionProvider.CloseConnection(IDbConnection conn)
   at NHibernate.Connection.DriverConnectionProvider.CloseConnection(IDbConnection conn)
   at NHibernate.Transaction.AdoNetTransactionFactory.ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork work, Boolean transacted)
   at NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.ExecuteWorkInIsolation(ISessionImplementor session, IIsolatedWork work, Boolean transacted)
   at NHibernate.Engine.Transaction.Isolater.DoIsolatedWork(IIsolatedWork work, ISessionImplementor session)
   at NHibernate.Engine.TransactionHelper.DoWorkInNewTransaction(ISessionImplementor session)
   at NHibernate.Id.TableGenerator.Generate(ISessionImplementor session, Object obj)
   at NHibernate.Id.TableHiLoGenerator.Generate(ISessionImplementor session, Object obj)
   at NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
   at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
   at NHibernate.Event.Default.DefaultSaveEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
   at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
   at NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
   at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
   at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
   at NHibernate.Impl.SessionImpl.Save(Object obj)

Well that’s not good. It appears the CloseConnection is being called, but the connection is null. Changing the call to ISessionFactory.OpenSession() does not produce this error.

The comment on the OpenSession(IDbConnection) method say to “Consider implementing your own IConnectionProvider”. In a multi-database environment this sounds like a viable option, but how do I determine which connection string I should use at a particular instance?

My gut reaction was to implement something similar to the NHibernate.Context.ICurrentSessionContext. This interface and the supporting classes in the NHibernate.Context namespace, allow the user to specify the application context during configuration. ISession CurrentSession() is then bound/unbound from a ISessionFactory based on the application context.

Here is a brief description of each of these classes.

Class Description
CallSessionContext Uses System.Runtime.Remoting.Messaging.CallContext methods object GetData(string) and SetData(string, object) to bind an ISession to an ISessionFactory
ManagedWebSessionContext Uses System.Web.HttpContext.Current to bind an ISession to an ISessionFactory. The users must bind/unbind from the static members.
ThreadLocalSessionContext Uses a static IDictionaryto bind a ISession to a ISessionFactory
ThreadStaticSessionContext Uses a static ISession variable to bind the ISessionFactory to a ISession. This class does not support multiple ISessionFactory objects per thread (Use CallSessionContext instead)
WcfOperationSessionContext Uses System.ServiceModel.OperationContext and a System.ServiceModel.IExtensionto bind a ISession to an ISessionFactory
WebSessionContext Uses System.Web.HttpContext.Current to bind an ISession to an ISessionFactory.

See the NHibernate Documentation here

I can definitely use these classes to manage my session, but I have a sneaking suspicion that creating my own application aware cache is a bit overkill.

What I really need, is to minimize the startup time of creating an ISessionFactory. It is general knowledge that you should create a ISessionFactory only once for a particular configuration. The problem I’m having is a ISessionFactory is bound to a ConnectionString. What I really need is to create the NHibernate.Cfg.Configuration only once per assembly.

After doing some research I came across a few articles such as this where people were caching a configuration on the file system. I wondered if I could partially configure the Configuration, without setting the connection.connection_string property. Then, at a later time, grab the Configuration and set the connection.connection_string when creating a ISessionFactory for a connection string I haven’t seen before.

I’m using FluentNHibernate here, but the same process applies for regular NHibernate.Cfg.Configuration

/// <summary>
/// Speeds up loading of ISessionFactory by loading Configuration only once per assembly.
/// </summary>
public sealed class SessionFactoryManager
{
   /// <summary>
   /// Flag shows when the SessionContextClass of ThreadStatic has been used
   /// </summary>
   private static bool sessionContextClassThreadStatic = false;

   /// <summary>
   /// The ISessionFactory cache, 
   /// only one session factory is created per Assembly/ConnectionString
   /// </summary>
   private static IDictionary<string, ISessionFactory> _sessionFactoryCache;

   public static IDictionary<string, ISessionFactory> SesssionFactoryCache
   {
       get
       {
           if (_sessionFactoryCache == null)
               lock (typeof(SessionFactoryManager))
               {
                  _sessionFactoryCache 
                      = new Dictionary<string, ISessionFactory>();
               }
           return _sessionFactoryCache;
       }
   }

   /// <summary>
   /// the Configuration cache, 
   /// only one Configuration is created per Assembly
   /// </summary>
   private static IDictionary<string, NHibernate.Cfg.Configuration> _configurationCache;

   public static IDictionary<string, NHibernate.Cfg.Configuration> ConfigurationCache
   {
       get 
       { 
           if(_configurationCache == null)
               lock (typeof(SessionFactoryManager))
               {
                   _configurationCache 
                       = new Dictionary<string, NHibernate.Cfg.Configuration>();
               }
           return _configurationCache; 
       }
   }

   /// <summary>
   /// Main entry point, caches the ISessionFactory based on the assembly full name
   /// </summary>
   /// <param name="connectionString">the connection string to use</param>
   /// <param name="contextClass">An enum with Call, ThreadStatic, Web, Wcf, ManagedWeb</param>
   /// <param name="assembly"></param>
   /// <returns></returns>
   public static ISessionFactory CreateSessionFactory(string connectionString, SessionContextClass contextClass, System.Reflection.Assembly assembly)
   {
       if (StringExtensions.IsNullOrWhiteSpace(connectionString))
           throw new ArgumentException(
               "The connectionString can not be null, empty or whitespace");
       string configurationKey = assembly.FullName;
       NHibernate.Cfg.Configuration config = null;
       // cache the configuration
       if (!SessionFactoryManager
             .ConfigurationCache
             .TryGetValue(configurationKey, out config))
       {
           var cfg = Fluently.Configure()
               .Database(
                   MsSqlConfiguration.MsSql2008
                   .ConnectionString(c => c.Is(connectionString)))
               .Mappings(m => m
                   .FluentMappings
                   .AddFromAssembly(assembly))
               .ExposeConfiguration(x =>
               {
                   // contextClass.Name() extension function maps enum value to a string:
                   // case SessionContextClass.Call:
                   //   return "call";
                   // case SessionContextClass.ThreadStatic:
                   //     return "thread_static";
                   // case SessionContextClass.Web:
                   //     return "web";
                   // case SessionContextClass.WCF:
                   //     return "wcf_operation";
                   x.SetProperty(
                       NHibernate.Cfg.Environment.CurrentSessionContextClass, 
                       contextClass.Name());
               }); ;

           config = cfg.BuildConfiguration();
           SessionFactoryManager.ConfigurationCache.Add(configurationKey, config);
       }

       // differentiate ISessionFactory by connection string 
       string factoryKey = string.Format("{0}|{1}", configurationKey, connectionString);
       // cache the session factory
       if (!SessionFactoryManager.SesssionFactoryCache.ContainsKey(factoryKey))
       {
           // make sure ThreadStatic is not being used across multiple ISessionFactory
           if (contextClass == SessionContextClass.ThreadStatic)
               if (sessionContextClassThreadStatic)
                   throw new ArgumentException("SessionContextClass.ThreadStatic does not support multiple session factories. Use SessionContextClass.Call instead");
               else
                  sessionContextClassThreadStatic = true;

           config.SetProperty(NHibernate.Cfg.Environment.ConnectionString, connectionString);
           var sessionFactory = config.BuildSessionFactory();

           // Add to the session factory cache
           SessionFactoryManager.SesssionFactoryCache.Add(factoryKey, sessionFactory);
       }
       return SessionFactoryManager.SesssionFactoryCache[factoryKey];
   }

Now in my global.asax.cs I can do the following to cache the Configuration and Default ConnectionString

// build the session factory for the customer model
// ConnectionString.FromConfig static method just wraps ConfigurationManager.ConnectionStrings["key"].ConnectionString
SessionFactoryManager.CreateSessionFactory<CustomerModel>(
    ConnectionString.FromConfig(WorkerManagementServiceConstants.HchbInitializationDatabaseKey),
    SessionContextClass.WCF);

All subsuquent calls to get the ISessionFactory are cached based on the assembly / connection string, but loading the ISessionFactory is significantly faster because the maps are already validated.

You can speed up this process even more by serializing the configuration to disk and loading/rebuilding the config as needed. See this article for information

You can then create a DataContext class to encapsulate the ISessionFactory creation and manage the ISession

/// <summary>
/// The SessionFactory for this instance
/// </summary>
protected ISessionFactory SessionFactory { get; set; }        

/// <summary>
/// The NHIbernate Session within this Model
/// </summary>
public ISession Session 
{ 
    get 
    { 
         if( NHibernate.Context.CurrentSessionContext.HasBind(SessionFactory))
             return SessionFactory.GetCurrentSession();
         var session = SessionFactory.OpenSession();
         NHibernate.Context.CurrentSessionContext.Bind(session);
         return session;
    } 
}

/// <summary>
/// Constructor to create instance of data context base class
/// </summary>
public DataContextBase(string connectionStringOrKeyName, SessionContextClass contextClass, Assembly assembly)
{
    Initialize(connectionStringOrKeyName, contextClass, assembly);
}

/// <summary>
/// Main entry point. Creates a ModelBase for the given connection string or configuration key. The mapping is pulled
/// from the assembly and the context class is used to determine session visibilty
/// </summary>
/// <param name="connectionStringOrKeyName"></param>
/// <param name="contextClass"></param>
/// <param name="assembly"></param>
protected void Initialize(string connectionStringOrKeyName, SessionContextClass contextClass, Assembly assembly)
{
   // get the connection string from the config or uses the string as the connection string
   string connectionString = ConnectionString.FromConfigOrDefault(connectionStringOrKeyName);

   // create the session factory from the connection string
   SessionFactory = SessionFactoryManager.CreateSessionFactory(connectionString, contextClass, assembly);           
}

Automapper Object Projections

When working with Entity Framwork or NHibernate we often need to convert our Model object to WCF DataContract objects. This process is easily facilitated through tools like AutoMapper, making redundant and boring tasks simple and fluid. I will illustrate a edge case when working with M:N relations (many to many) and mapping to/from N:1 relations (many to one).

In the class list below, we have a the ModelWorker and ModelLocation classes which share a N:M relationship through ModelWorkerLocation. In the DTO we have the ContractWorker and ContractLocation which share a N:1 relation through the ContractLocationList property. If we were to use the ContractWorker and ContractLocation in WCF, we would of course add [DataContract] and [DataMember] attributes to all properties we wish to expose.

public class ModelWorker
{
    public int Id { get; set; }
    public ModelWorkerLocation[] ModelWorkerLocationList { get; set; }
}

public class ModelWorkerLocation
{
    public int Id { get; set; }
    public ModelLocation ModelLocation{get;set;}
    public ModelWorker ModelWorker {get;set;}
}

public class ModelLocation
{
    public int Id { get; set; }
}

public class ContractWorker
{
    public int Id { get; set; }
    public ContractLocation[] ContractLocationList { get; set; }
}

public class ContractLocation
{
   public int Id { get; set; }
}

Below we will map from the model to the DataContract producing a 1:N relation from a N:M. I found this mapping direction to be the most intuitive of the two, since you only need to access the ModelLocation property of the ModelWorkerLocation object, and pass that on to AutoMapper.

ModelWorker mw = new ModelWorker { Id = 1 };
ModelLocation ml = new ModelLocation { Id = 2 };
ModelLocation ml1 = new ModelLocation { Id = 3 };
ModelLocation ml2 = new ModelLocation { Id = 4 };

mw.ModelWorkerLocationList = new ModelWorkerLocation[]
{
      new ModelWorkerLocation{Id = 5, ModelLocation=ml, ModelWorker = mw},
      new ModelWorkerLocation{Id = 6, ModelLocation=ml1, ModelWorker = mw},
      new ModelWorkerLocation{Id = 7, ModelLocation=ml2, ModelWorker = mw}
};

// Pretty simple here, just create maps between the 
// ModelLocation -> ContractLocation
// ModelWorker -> ContractWorker
// ModelWorkerLocation -> ModelLocation -> ContractLocation
Mapper.CreateMap<ModelLocation, ContractLocation>();
Mapper.CreateMap<ModelWorker, ContractWorker>()
      .ForMember(
          dest=>dest.ContractLocationList,
          source=>source.MapFrom(w=>
               w.ModelWorkerLocationList
                .Select(wll=>wll.ModelLocation)));
Mapper.AssertConfigurationIsValid();
var a = Mapper.Map<ModelWorker, ContractWorker>(mw);
Console.Write(a);

The more difficult of the two mappings is to map the Contract 1:N relation to the Model N:M relation because we have to create the ModelWorkerLocation object between. To make things more difficult, ModelWorkerLocation has a reference back to the ModelWorker which will need to be recreated after the mapping has occurred. We will use the AfterMap method to take care of this reference.

To make sure AutoMapper doesn’t throw an error, we mark the ModelWorker property of the ModelWorkerLocation object with Ignore().

ContractWorker cw = new ContractWorker { Id = 1 };
ContractLocation cl1 = new ContractLocation { Id = 2 };
ContractLocation cl2 = new ContractLocation { Id = 3 };
ContractLocation cl3 = new ContractLocation { Id = 4 };
cw.ContractLocationList = new ContractLocation[] {cl1, cl2, cl3};

Mapper.CreateMap<ContractWorker, ModelWorker>()
	.ForMember(dest => dest.ModelWorkerLocationList,
                   source => source.MapFrom(dest=>dest.ContractLocationList))
	.AfterMap((source, dest)=>
	{
		foreach (var mwl in dest.ModelWorkerLocationList)
			mwl.ModelWorker = dest;
	});

Mapper.CreateMap<ContractLocation, ModelWorkerLocation>()
	.ForMember(dest => dest.Id, source => source.Ignore())
	.ForMember(dest => dest.ModelLocation, source => source.MapFrom(m => m))
	.ForMember(dest => dest.ModelWorker, source => source.Ignore());

Mapper.CreateMap<ContractLocation, ModelLocation>();

Mapper.AssertConfigurationIsValid();

var b = Mapper.Map<ContractWorker, ModelWorker>(cw);
Console.WriteLine(b);

There you have it, N:M to N:1 and back again.