Castle Windsor Nhibernate Facility Lazy loading

1.6k views Asked by At

I am migrating my mvc web app to use Nhibernate Facility to manage Nhibernate sessions.

I am encountering this strange problem;

When I register SessionWebModule under web.config/ httpmodules via:

<add name="NHibernateSessionWebModule"
type="Castle.Facilities.NHibernateIntegration.Components.Web.SessionWebModule,
Castle.Facilities.NHibernateIntegration" />

System is unable to lazy load objects. I get no session exception.

If I don't add this to web.config lazy loading is working fine. Everything part from this seems to be OK as far as regitering Windsor container and registering Nhibernate Facility goes. Nhibernate Facility is able to provide session manager and Windsor container is able to resolve objects.

Ofcourse, without SessionWebModule Nhibernate Facility is near useless for me as in this situation it is not able to properly manage sessions. I see datareader is allready open type exceptions which are no good..

I am stuck and need to urgently get past this problem I will appreciate any help from you.

I am including below some sections of my configuration and code to give more information

Web.config:

<castle>
        <facilities>
            <facility id="nhibernatefacility" isWeb="false"
type="Castle.Facilities.NHibernateIntegration.NHibernateFacility,
Castle.Facilities.NHibernateIntegration">
                <factory id="nhibernate.factory">
                    <settings>
                        <item
key="connection.provider">NHibernate.Connection.DriverConnectionProvider</
item>
                        <item
key="connection.driver_class">NHibernate.Driver.SqlClientDriver</item>
                        <item key="connection.connection_string">Data
Source=zzz;Database=xxx;Trusted_Connection=True;</item>
                        <item
key="dialect">NHibernate.Dialect.MsSql2005Dialect</item>
                        <item
key="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory,
NHibernate.ByteCode.LinFu</item>
                      </settings>
                    <assemblies>
                        <assembly>AppWeb.Domain</assembly>
                    </assemblies>
                </factory>
            </facility>
        </facilities>
    </castle>

<system.webServer>
        <validation validateIntegratedModeConfiguration="false" />
        <modules runAllManagedModulesForAllRequests="true">
              <add name="NHibernateSessionWebModule"
type="Castle.Facilities.NHibernateIntegration.Components.Web.SessionWebModule,
Castle.Facilities.NHibernateIntegration" />
        </modules>
</sytem.webServer>

Global.asax

public class MvcApplication : System.Web.HttpApplication,
IContainerAccessor
    {
        private static IWindsorContainer container;

        public IWindsorContainer Container
        {
            get { return container; }
        }

        void Application_Error(Object sender, EventArgs e)
        {
            Logger.Error(Server.GetLastError());
        }

        public static void RegisterRoutes(RouteCollection routes)
        {
            #region Ignores
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.IgnoreRoute("admin/{*url}");
            #endregion

            routes.MapRoute(
                "Default",
                "{controller}/{action}/{id}",
                new { controller = "Home", action = "Main", id = "" },
                new { controller = @"[^\.]*" }
            );
        }

        protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
            log4net.Config.XmlConfigurator.Configure();
            SetupWindsor();
        }

        private void SetupWindsor()
        {
            container = new WindsorContainer(new XmlInterpreter());

            container.Register(
                        AllTypes
                            .FromAssemblyContaining<UserRepository>()
                            .Where(t => t.Name.EndsWith("Repository",
StringComparison.Ordinal))
                            .WithService
                            .FirstInterfaceOnType()
                            .Configure(r =>
r.LifeStyle.PerWebRequest),

AllTypes.FromAssembly(Assembly.GetExecutingAssembly())
                            .BasedOn<IController>()
                            .Configure(c =>
c.LifeStyle.PerWebRequest),

                    );
                    //.AddFacility<TransactionFacility>();

            ControllerBuilder.Current.SetControllerFactory(new
WindsorControllerFactory(container));
        }
    }

Lazy loading exception:

[LazyInitializationException: Initializing[AppWeb.Domain.City#31135]- Could not initialize proxy - no Session.] NHibernate.Proxy.AbstractLazyInitializer.Initialize() +138 NHibernate.Proxy.AbstractLazyInitializer.GetImplementation() +37 NHibernate.ByteCode.LinFu.LazyInitializer.Intercept(InvocationInfo info) +72 CityProxy.get_Name() +143 ASP.views_tour_filters_ascx.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\wwwroot\AppWeb\AppWeb.Web\Views\Tour \Filters.ascx:14 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +256 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19 System.Web.UI.Control.Render(HtmlTextWriter writer) +10 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +134 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +19 System.Web.UI.Page.Render(HtmlTextWriter writer) +29 System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +59 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +99 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1266

3

There are 3 answers

0
Geoff On

If you're using MVC, I use an action filter to close my nhibernate sessions

public class NHibernateSessionAttribute : ActionFilterAttribute
{
    public NHibernateSessionAttribute()
    {
        Order = 100;
    }


    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        if (filterContext.IsChildAction) return;

         SessionSource.EndContextSession();
    }
}

SessionSource is where I'm managing creating my sessions... and the SessionSource.EndContextSession() method essentially calls:

    public static void EndContextSession()
    {
        var session = CurrentSessionContext.Unbind(Factory);
        if (session != null && session.IsOpen)
        {
            try
            {
                if (session.Transaction != null && session.Transaction.IsActive)
                {
                    // an unhandled exception has occurred and no db commit should be made
                    session.Transaction.Rollback();
                }
            }
            finally
            {
                session.Close();
                session.Dispose();
            }
        }
    }
3
AudioBubble On

It's by design. You have to keep your session open.

If you are doing web, I suggest you to open the session at the begin of the request and close it at the end.

Get the samples from this article: http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx

1
Bartol On

I belive you have to set the isWebattribute to true:

<facility id="nhibernatefacility" isWeb="true" type="Castle.Facilities.NHibernateIntegration.NHibernateFacility, Castle.Facilities.NHibernateIntegration">