Click here to Skip to main content
15,891,136 members
Articles / Web Development / ASP.NET

NHibernate sessions in ASP.NET MVC

Rate me:
Please Sign up or sign in to vote.
4.00/5 (1 vote)
17 May 2010CPOL1 min read 25.4K   15   1
NHibernate sessions in ASP.NET MVC

If you've used NHibernate in a ASP.NET MVC project, you probably encountered the problem of keeping session open in the view in order to retrieve model data (even though if session is open then the view actually makes calls to the db under the hood, which maybe is not very MVC. But that's another story).

The idea is to pass controllers an instance of a NHibernate session which is unique for the HTTP request.

First off, we need to "hijack" the ASP.NET mechanism that instantiates controllers to pass something in the constructor. In this case, it's a ISession, but it could well be a repository class (which in turn gets a ISession passed in its constructor).

So a controller would look like this:

C#
public class MyController : Controller
{
    ISession session;

    public MyController(ISession session)
    {
        this.session = session;
    }
...

I've used Unity dependency container to manage the instantiation of controllers. ASP.NET MVC lets you do that by overriding the DefaultControllerFactory.

This is as simple as writing this class:

C#
public class UnityControllerFactory : DefaultControllerFactory
{
    UnityContainer container;

    public UnityControllerFactory(UnityContainer container)
    {
        this.container = container;
    }

    protected override IController GetControllerInstance
	(RequestContext requestContext, Type controllerType)
    {
        IController controller = null;
        if (controllerType != null)
        {
            controller = this.container.Resolve(controllerType) as IController;
        }
        return controller;
    }
}

To make the session instance "singleton" for the HTTP request, all I need to do is write a simple custom lifetime manager for Unity:

C#
public class PerRequestLifetimeManager : LifetimeManager
{
    public const string Key = "SingletonPerRequest";

    public override object GetValue()
    {
        return HttpContext.Current.Items[Key];
    }

    public override void SetValue(object newValue)
    {
        HttpContext.Current.Items[Key] = newValue;
    }

    public override void RemoveValue() {} // this does not appear to be used ...
}

Let's get everything together in Global.asax. We need to register ISession in Unity configuration. It should inject it using a factory method (OpenSession method of a ISessionFactory instance).

Then we need to tell MVC to use our Controller factory, passing the Unity container of our ASP.NET MVC application.

To close open sessions, we add some code in the Application_EndRequest.

Here's the code to put in our Global.asax file.

C#
protected void Application_Start()
{
    this.container = new UnityContainer();
    container.RegisterType<isession>(
        new PerRequestLifetimeManager(),
        new InjectionFactory(c => {
            ISessionFactory sessionFactory = 
	         NHConfigurator.CreateSessionFactory(); // NHConfigurator is my 
							// helper conf class
            return sessionFactory.OpenSession();
        }));

    ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory 
(this.container));

    AreaRegistration.RegisterAllAreas();

    RegisterRoutes(RouteTable.Routes);
}

protected void Application_EndRequest(object sender, EventArgs e)
{
    Object sessionObject = HttpContext.Current.Items[PerRequestLifeTimeManager.Key];
    if (sessionObject != null)
    {
        ISession currentSession = sessionObject as ISession;
        if (currentSession != null)
        {
            currentSession.Close();
        }
    }
} 

Hope this helps!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Italy Italy
Software architect. At present working on C# development, with mainly Asp.net Ajax and MVC user inteface. Particularly interested in OOP, test driven, agile development.

Comments and Discussions

 
GeneralRe session end Pin
Ajay Kale New9-Sep-10 4:18
Ajay Kale New9-Sep-10 4:18 
Hi

I have a query regarding redirection to Login page, which I am not being able to trace out.

When I click on any of the tab in my application (which internally loads a new aspx page) sometimes it
is redirected to Login.aspx, which is unexpected. Couldnot debug why this is happening even by javascript alerts and C# debugging statements.

Below is the view source piece from Login.aspx, just for clue
<form name="Form1" method="post" action="login.aspx?ReturnUrl=%2fValuations%2fToDoList.aspx" id="Form1">

Valuations is the dll of application and ToDoList.aspx is the tab page I clicked which should load, but suddenly Login.aspx page is displayed. I traced the complete solution project.

- in web.config
<authorization>
<deny users="?"/>

</authorization>

- -suddenly while traversing in the application it redirects to login.aspx including return url as stated earlier and also if we keep the application idle for 5-10 mins and clicks somewhere, still redirects....

- - we have also AjaxPro.dll for async calls.

- when the login.aspx page is not closed then, below logger statements are seen after 5 mins
-public Global()
{
_log4netLogger.Debug("Global:Global");
InitializeComponent();
}
- catch of Session_End (because System.Web.HttpContext.Current.Application["userPool"]; is null)
- Application_End



Can you please help me...?

- Ajay K

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.