20100316

Binding Fluent NHibernate session to WCF call

First you should read previous post about WCF Session.

You have to modify the example provided in mentioned post. While binding the Endpoint Extension to the Call Context you need to open and close session.

public class ExampleEndpointContextInitializer : ICallContextInitializer
    {
        public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
        {
            bool found = false;
            foreach (IExtension extension in OperationContext.Current.Extensions)
            {
                if (extension is ExampleEndpointExtension)
                {
                    found = true;
                    break;
                }
            }
            if (!found)
            {
                OperationContext.Current.Extensions.Add(new ExampleEndpointExtension());
            }
            return ExampleSessionProvider.Instance.OpenSession();
        }

        public void AfterInvoke(object correlationState)
        {
            ExampleSessionProvider.Instance.CloseSession(((ISession)correlationState));
            ((IDisposable)correlationState).Dispose();
        }
    }

The class below will bind Fluent NHibernate session to HttpContext if exists otherwise it will try to bind to WCF context.

public class ExampleSessionProvider
    {
        private const string SESION_KEY = "SESSION_KEY";

        private ExampleSessionProvider()
        {

        }

        private static ExampleSessionProvider instance;

        public static ExampleSessionProvider Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new ExampleSessionProvider();
                }
                return instance;
            }
        }

        private ISessionFactory sessionFactory;

        public void CreateSessionFactory()
        {
            sessionFactory = Fluently.Configure();                
                .ExposeConfiguration(BuildSchema)
                .BuildSessionFactory();
            // add more configuration options above !!!
        }

        public ISession GetSession()
        {
            if (HttpContext.Current != null)
            {
                return sessionFactory.GetCurrentSession();
            }
            if (OperationContext.Current != null)
            {
                foreach (IExtension extension in OperationContext.Current.Extensions)
                {
                    if (extension is ExampleEndpointExtension)
                    {
                        if (((ExampleEndpointExtension)extension).State.ContainsKey(SESION_KEY))
                        {
                            return (ISession)((ExampleEndpointExtension)extension).State[SESION_KEY];
                        }
                    }
                }
            }
            return null;
        }

        public ISession OpenSession()
        {
            ISession session = sessionFactory.OpenSession();

            if (HttpContext.Current != null)
            {
                ManagedWebSessionContext.Bind(
                    HttpContext.Current, session);
            }
            else if (OperationContext.Current != null)            
            {
                foreach (IExtension extension in OperationContext.Current.Extensions)
                {
                    if (extension is ExampleEndpointExtension)
                    {
                        if (((ExampleEndpointExtension)extension).State.ContainsKey(SESION_KEY))
                        {
                            ((ExampleEndpointExtension)extension).State.Remove(SESION_KEY);
                        }
                        ((ExampleEndpointExtension)extension).State.Add(SESION_KEY, session);
                    }
                }
            }
            return session;
        }

        public void CloseSession()
        {
            CloseSession(null);
        }

        public void CloseSession(ISession session)
        {
            if ((session != null) && (HttpContext.Current != null))
            {
                session = ManagedWebSessionContext.Unbind(HttpContext.Current, sessionFactory);
            }
            if (session != null)
            {
                if (session.Transaction != null &&
                    session.Transaction.IsActive)
                {
                    session.Transaction.Rollback();
                }
                else
                {
                    session.Flush();
                }
                session.Close();
            }
        }

        private static void BuildSchema(Configuration config)
        {
            config.SetProperty("current_session_context_class", "managed_web");
        }
    }

Before binding to HttpContext you need to create HttpModule described in post about Binding Fluent NHibernate session to HttpContext or you can remove parts related to HttpContext and bind always to WCF call.

No comments: