Sunday, January 25, 2015

WCF with Fluent NHibernate and StructureMap - Unit of work - Session/Session factory transaction


-- Content yet to be re-structured....

This tells about the IOC registration to be invoked once in WCF . in Web application it's easy because this has session in it when browser is opend, but WCF with Basic binding doesn't have that features.

so to make IOC registration/ on each service method this was to be called. and again WCF service was to invoke different connection based on country code supplied in service method, so IOC has to be reset with new connection string each time service method was called.

Like Webapplication, I could have done this..like creating new registry for different conenction (DB) for different countries. and in Applicaiton_Start event invoke IOC and all registry . then using  repositry and single unit of work parttern- I could have used the DAO layer to do the transaction.

Problem is : once the service method was invoked and it did the operation, session was getting closed. This is because we knew, Service has no session and it can't work like (Per session Instance mode) like web application.

so each call acts as new session and once service method is invoked, everything is lost. session is closed.

So I had to use the repository class's constructure to use Isessionfactory object opening a new session everytime it's called and begin new transaction. sets this in repository .session object and use this in calling method to commit or rollback it.

and to Make IOC registration call only once/ I had to make it singleton by using static object so that it does not get called every time  when service method was called.

Another problem was: everytime IOC was called the sessionfactory was called everytime and session was getting opened that many time with begin transaction. which i had to commented out and use it in repsiotry class to open session every time .  (

x.For<ISessionFactory>().Singleton()
                            .Use(() => new NHibernateHelper().BuildSessionfactory());

                        //x.For<ISession>().HybridHttpOrThreadLocalScoped()
                        //    .Use(ctx =>
                        //    {
                        //        var session = ctx.GetInstance<ISessionFactory>().OpenSession();
                        //        session.FlushMode = FlushMode.Commit;
                        //        session.BeginTransaction();
                        //        return session;
                        //    });

Commented section was getting called very time. I could have used the same pattern but when Isession was used this remains in open state and transaction is active. and once it's done with SQL transaction it was getting closed, so had to call IOC registratoin every time to create new Isession instance.

Little more details with


Next time when service method is called, again this will create session factory for a single country DB connection. this will check if Sessionfactory already create, this will just return the earlier created sessionfactory else will create a new one ( Singleton way)

then in repository class (Constructor), it will create new session of existing/new session factory and will do the Get/Update method.

when session.begintransaction gets called, Transaciton -gets active. and on commit it becomes false.

This is how in WCF call/ Bootstrapper.RegisterIOC can be called only once as we would have done in WebApplication by calling in "Applicaiotn_Start" event. and Webservice won't consume memory/ or will have headache of reseting sessionfactory and session all lthe time, service method gets called.


Example:


 public class Repository : IRepository, IDisposable
    {
        public ISession _session { get; set; }
       // public Repository(ISession session) { _session = session;}
        private ISessionFactory SessionFactory;
        public Repository()
        {
            SessionFactory = ObjectFactory.GetInstance<ISessionFactory>();
            _session = SessionFactory.OpenSession(); // Sets this in Repostiory session so that can be rollbacked or commited from service/client layer.
            _session.BeginTransaction();

        }
}

Boostraper:
public static class Bootstrapper
    {
        private static object _instance;
        private static object syncRoot = new Object();



        public static object Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (syncRoot)
                    {
                        // if (_instance == null)
                        // instance = new Singleton();
                    }
                }

                return _instance;
            }
        }

        public static void RegisterIoC()
        {
            if (_instance == null)
            {
                _instance = "US";  -- for US only once created.
                ObjectFactory.Initialize(x =>
                    {
                        //This needs to be configured to make user of multiple string. and RegisterIOC will only be called once when this is initilalised.
so below method won't get called every time as we used to do in service method.
                        x.For<ISessionFactory>().Singleton()
                            .Use(() => new NHibernateHelper().BuildSessionfactory());

                        //x.For<ISession>().HybridHttpOrThreadLocalScoped()
                        //    .Use(ctx =>
                        //    {
                        //        var session = ctx.GetInstance<ISessionFactory>().OpenSession();
                        //        session.FlushMode = FlushMode.Commit;
                        //        session.BeginTransaction();
                        //        return session;
                        //    });
                        x.For<IMS001>().Use<MS001>();
                        //x.For<IMS002>().Use<MS002>();
                        x.For<IMS004>().Use<MS004>();
                        x.For<IMS020>().Use<MS020>();
                        x.For<IMS021>().Use<MS021>();
                        x.For<IMS022>().Use<MS022>();
                        x.For<IMS024>().Use<MS024>();
                        x.For<IMS025>().Use<MS025>();
                        x.For<IMS026>().Use<MS026>();
                        x.For<IMSHelper>().Use<MSHelper>();

                        x.For<IRepository>().Use<Repository>();
                        x.Scan(y =>
                        {
                            y.TheCallingAssembly();
                            y.LookForRegistries();
                        });

                    });

            }
        }


        //public static void Initialize()
        //{
        //    throw new NotImplementedException();
        //}
    }

    public class SqlServerRegistry : Registry
    {
        public SqlServerRegistry()
        {

            //For<ISession>().HybridHttpOrThreadLocalScoped()
            //   .Use(ctx =>
            //   {
            //       var session = ctx.GetInstance<ISessionFactory>().OpenSession();
            //       session.FlushMode = FlushMode.Commit;
            //       session.BeginTransaction();
            //       return session;
            //   });

        }

    }

Example of Service method:
Calling method:
   private void CommitTransaction()
        {
            ISession session = ((Hierarchy_Services.Infrastructure.BusinessLogic.Repository)_repository)._session;
            if (session != null)
            {
             
                try
                {
                    if (session.IsOpen)
                    {
                        if (session.Transaction.IsActive)
                   
                           session.Transaction.Commit();
                       // session.BeginTransaction();
                     
                    }
                }
                catch (Exception ex)
                {
                    logger.Error(GetErrorMessage(ex));
                    RollbackTransaction();
                }
            }
        }
        private void RollbackTransaction()
        {
            ISession session = ((Hierarchy_Services.Infrastructure.BusinessLogic.Repository)_repository)._session; //this is where you capture the repository session.
         
            if (session.IsOpen )
            {
                if (session.Transaction != null && session.Transaction.IsActive)
                {
                    session.Transaction.Rollback();
                }
            }
        }
        private void CloseSession()
        {
            ISession session = ((Hierarchy_Services.Infrastructure.BusinessLogic.Repository)_repository)._session;
            if (session !=null && session.IsOpen )
            {
                  session.Dispose();
            }
        }

Public string ReturnMethod (string inputparameter)
{
InvokeFactory(request.countryCode.ToUpper()); -- this is where we used to know when which DB connection is going to used (country based)
}


 private void InvokeFactory(string countryCode, int divNo)
        {
            setCountryConfig(countryCode, divNo);
            Bootstrapper.RegisterIoC();
            _repository = ObjectFactory.GetInstance<IRepository>();
          //   session = ObjectFactory.GetInstance<ISession>();
            SessionFactory = ObjectFactory.GetInstance<ISessionFactory>();
            helper = new PositionHierarchyHelper(_repository, SessionFactory);
        }

Mainly you are passing the Isessionfactory object to repository class and there you are creating a new session and begin transaction. do operation and on calling method (page/service) you are getting the session (Isession) of repository partern and commit it or rollingh it back.

To make Single ton IOC registratoin and sessionfactory

public class NHibernateHelper
    {
        private static ISessionFactory _sessionFactory;

        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)

                    InitializeSessionFactory();
                return _sessionFactory;
            }
        }

        private static void InitializeSessionFactory()
        {
            _sessionFactory = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008
                  .ConnectionString(
                  @"Server=(local);initial catalog=xxxxx;
  user=xxxxx;password=xxxxx;") // Modify your ConnectionString
                              .ShowSql()
                )
                .Mappings(m =>
                          m.FluentMappings
                              .AddFromAssemblyOf<Program>())
                .ExposeConfiguration(cfg => new SchemaExport(cfg)
                                                .Create(true, true))
                .BuildSessionFactory();
        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }

No comments:

Post a Comment