I recently started working on a project which I decided to use nHibernate and springframework for .Net with MVC. Though I had experience working with the springframework with ASP.NET, applying MVC had its issues.
Concerns at Deployment
Few things that you should keep in mind is that MVC projects works only under Integrated Pipeline mode. But the basic configuration for Springframework supports both modes Classic mode or Integreated. This conflict occurred as when I tried to deploy the project.
In order to solve that matter I had to assign the preCondition attribute in handlers. Such as,
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules runAllManagedModulesForAllRequests="true">
<add name="Spring" type="Spring.Context.Support.WebSupportModule, Spring.Web" />
<add name="OpenSessionInView" type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, Spring.Data.NHibernate32" />
<add name="SpringModule" type="Spring.Context.Support.WebSupportModule, Spring.Web"/>
</modules>
<handlers>
<remove name="PageHandlerFactory"/>
<remove name="ContextMonitor"/>
<remove name="WebServiceHandlerFactory"/>
<add name="PageHandlerFactory" preCondition="integratedMode" verb="*" path="*.aspx" type="Spring.Web.Support.PageHandlerFactory, Spring.Web" />
<add name="ContextMonitor" preCondition="integratedMode" verb="*" path="ContextMonitor.ashx" type="Spring.Web.Support.ContextMonitor, Spring.Web" />
<add name="WebServiceHandlerFactory" preCondition="integratedMode" verb="*" path="*.asmx" type="Spring.Web.Services.WebServiceHandlerFactory, Spring.Web" />
</handlers>
</system.webServer>
After adding the above code in the web.config, web site started working fine. I forgot to mention about how to configure pipeline in IIS.
- Open IIS: type “inetmgr” in the Run command screen
- Expand the server node
- Go to the application pool
- Select the application pool that is selected for your web site
- Double click on the pool
- Change the value in “Managed pipeline mode” dropdown to “Integrated”
A common error
Then I got this error,
No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
This is a very common error, but the main reason would be that, springframework can’t detect the hibernate session.
- First check for the OpenSessionView module is existing in the web.config file. If it is not then add this in modules section
- Secondly check whether the service layer calls are wrapped with a transaction attribute. It does not matter whether the call is read or write to the database.
I am telling this because I have a solution that have MVC Web Site and a windows application that uses the same data access library. All the configuration worked perfectly with the MVC after setting up as I have mentioned in the above of this post. But when it comes to the windows application it was throwing this error. Then I managed to get rid of it by specifying the “Transaction” attribute on the particular method that was called in the windows application.
I assume the reason behind this is windows applications are bound to maintain a dedicated session for the user, there’s no multiple session handling.
Transaction attribute
With the below configuration in your data access config file, transaction is enabled.
NOTE: WORDPRESS DOES NOT ALLOW ENTERING “Object” elements in anyway, so I have change that to “hobject”. when you use make sure to rename it back.
<hobject id="transactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate32">
<property name="DbProvider" ref="DbProvider"/>
<property name="SessionFactory" ref="NHibernateSessionFactory"/>
</hobject>
I assume you have the DbProvider and NHibernateSessionFactory objects defined. If not do as follows, Following is the DbProvider object, if you look at the database connection details they are passed as parameters using ${db.user} as an example. This way you get to change the db config details even after deployment, otherwise you will have to do a release, as the config data is in the compiled data-access-config.xml file. How this is done I have explain in this post.
<db:provider id="DbProvider" provider="MySql.Data.MySqlClient" connectionString="server=${db.datasource}; User Id=${db.user};database=${db.database};password=${db.password};Persist Security Info=True"/>
<hobject id="NHibernateSessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate32">
<property name="DbProvider" ref="DbProvider"/>
<property name="MappingAssemblies">
<list>
<value>MyApp.DataAccess</value>
</list>
</property>
<property name="HibernateProperties">
<dictionary>
<entry key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider"/>
<entry key="dialect" value="NHibernate.Dialect.MySQLDialect"/>
<entry key="hibernate.connection.driver_class" value="NHibernate.Driver.MySqlDataDriver"/>
<entry key="hibernate.current_session_context_class" value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate32"/>
<entry key="use_proxy_validator" value="false"/>
<entry key="format.sql" value="true" />
<entry key="show_sql" value="true" />
</dictionary>
</property>
<property name="ExposeTransactionAwareSessionFactory" value="true" />
</hobject>
To support transaction in service layer add the following configuration in the service layer config.
<tx:attribute-driven/>
Then add the [Transaction] attribute on the methods declaration where you want to enable transaction in the service layer. And make sure that you use CurrentSession.Flush() method at the end of those methods to commit all changes to the database.
Happy coding!!!
(I am tired now 2 posts at a stretch ;-))