4

I'm still pretty new to these technologies. The real problem here is how to manage the sessions per thread in the console app. Currently, if I run it as a single thread then all is well. As soon as I switch to a multi-threaded model, I'll start to see contention at the session level (because the Session object is not theadsafe by design) KeyNotFound exceptions (among others) start to get thrown.

In a web app, you'd do something like this:

    /// <summary>
    /// Due to issues on IIS7, the NHibernate initialization cannot reside in Init() but
    /// must only be called once.  Consequently, we invoke a thread-safe singleton class to
    /// ensure it's only initialized once.
    /// </summary>
    protected void Application_BeginRequest(object sender, EventArgs e)
    {
        NHibernateInitializer.Instance().InitializeNHibernateOnce(
            () => InitializeNHibernateSession());
    }

    /// <summary>
    /// If you need to communicate to multiple databases, you'd add a line to this method to
    /// initialize the other database as well.
    /// </summary>
    private void InitializeNHibernateSession()
    {            

        var path = ConfigurationManager.AppSettings["NHibernateConfig"];
        NHibernateSession.Init(
            webSessionStorage,
            new string[] { Server.MapPath("~/bin/foo.Data.dll") },
            new AutoPersistenceModelGenerator().Generate(),
            Server.MapPath("~/App_Configuration/" + path ));
    }

// sample of my console app... very simple
static void Main(string[] args)
{
  InitializeNHibernateSession();
  while(true)
  {
    Task.Factory.StartNew(() => SomeAwesomeLongRunningPieceOfWork());
  }
}

Which essentially executes the initialization once per thread (web request) in the global.asax.

Any ideas on how to set this (the session management) up in a console app?

longda
  • 10,153
  • 7
  • 46
  • 66
  • Presumably in the console app you're managing threads yourself? Surely the threads you create have an entry point that could call into the initialize method in the same was as Application_BeginRequest. It would be helpful if we had more information on how you're managing threads in your console app :) – MattDavey Aug 26 '11 at 08:01
  • @MattDavey - I'll update the OP to reflect my setup. – longda Aug 26 '11 at 18:07

1 Answers1

7

This worked for me:

// Three threads:
for (int i = 0; i < 3; i++)
{
   Thread curThread = new Thread(StartThread);
   curThread.Start();
}

private void StartThread()
{
      NHibernateInitializer.Instance().InitializeNHibernateOnce(InitializeNHibernateSession);
      SomeAwesomeLongRunningPieceOfWork();            
}

private void InitializeNHibernateSession()
{
   var path = ConfigurationManager.AppSettings["NHibernateConfig"];

   NHibernateSession.Init(
      new ThreadSessionStorage(),
      new string[] { "foo.Data.dll" },
      new AutoPersistenceModelGenerator().Generate(),
      "./App_Configuration/" + path);
}

The key was this class, which I got from:

http://groups.google.com/group/sharp-architecture/browse_thread/thread/ce3d9c34bc2da629?fwc=1 http://groups.google.com/group/sharp-architecture/browse_thread/thread/51794671c91bc5e9/386efc30d4c0bf16#386efc30d4c0bf16

public class ThreadSessionStorage : ISessionStorage
{
    [ThreadStatic]
    private static ISession _session;
    public ISession Session
    {
        get
        {
            return _session;
        }
        set
        {
            _session = value;
        }
    }

    public ISession GetSessionForKey(string factoryKey)
    {
        return Session;
    }

    public void SetSessionForKey(string factoryKey, ISession session)
    {
        Session = session;
    }

    public IEnumerable<ISession> GetAllSessions()
    {
        return new List<ISession>() { Session };
    }
}

And it works just fine.

Juan Arias
  • 666
  • 7
  • 16