1

I have encounter a strange problem. I've set up and MVC 4 app uisng NHibernate followed by instructions in ASP.NET MVC4 and the Web API published by apress.

I manage session for actions using controller attribute named [LoggingNhibernateSessionAttribute]. It works well and I can do CRUD operations with NHibernate.

But problem arise when I add an authorize attribute to HomeController which redirects to login page. at the moment an exception occurs indicating

"No session bound to the current context"

I looked a lot at my code. but I couldn't understand why session doesn't bound to current context.

public class LoggingNHibernateSessionAttribute : ActionFilterAttribute
{
    private readonly IActionLogHelper _actionLogHelper;
    private readonly IActionExceptionHandler _actionExceptionHandler;
    private readonly IActionTransactionHelper _actionTransactionHelper;

    public LoggingNHibernateSessionAttribute()
        : this(WebContainerManager.Get<IActionLogHelper>(),
        WebContainerManager.Get<IActionExceptionHandler>(),
        WebContainerManager.Get<IActionTransactionHelper>())
    {
    }

    public LoggingNHibernateSessionAttribute(
        IActionLogHelper actionLogHelper,
        IActionExceptionHandler actionExceptionHandler,
        IActionTransactionHelper actionTransactionHelper)
    {
        _actionLogHelper = actionLogHelper;
        _actionExceptionHandler = actionExceptionHandler;
        _actionTransactionHelper = actionTransactionHelper;
    }

    public override void OnActionExecuting(ActionExecutingContext actionExectingContext)
    {
        _actionLogHelper.LogEntry(actionExectingContext.ActionDescriptor);
        _actionTransactionHelper.BeginTransaction();
    }

    public override void OnActionExecuted(ActionExecutedContext actionExecutedContext)
    {
        _actionTransactionHelper.EndTransaction(actionExecutedContext);
        _actionTransactionHelper.CloseSession();
        _actionExceptionHandler.HandleException(actionExecutedContext);
        _actionLogHelper.LogExit(actionExecutedContext.ActionDescriptor);
    }
}

ActionTransactionHelper

public ActionTransactionHelper(
        ISessionFactory sessionFactory,
        ICurrentSessionContextAdapter currentSessionContextAdapter)
    {
        _sessionFactory = sessionFactory;
        _currentSessionContextAdapter = currentSessionContextAdapter;
    }

    public void BeginTransaction()
    {
        var session = _sessionFactory.GetCurrentSession();
        if (session != null)
        {
            session.BeginTransaction();
        }
    }

and here how I bind session to current sessionContext:

private ISession CreateSession(IContext context)
    {
        var sessionFactory = context.Kernel.Get<ISessionFactory>();
        if (!CurrentSessionContext.HasBind(sessionFactory))
        {
            // Open new ISession and bind it to the current session context
            var session = sessionFactory.OpenSession();
            CurrentSessionContext.Bind(session);
        }
        return sessionFactory.GetCurrentSession();
    }

does anyone have any idea?

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
Hashem Aboonajmi
  • 13,077
  • 8
  • 66
  • 75

2 Answers2

1

The issue here is related to the execution order of IFilter Attributes, described here: Understanding Action Filters (cite below)

The ASP.NET MVC framework supports four different types of filters:

  1. Authorization filters – Implements the IAuthorizationFilter attribute.
  2. Action filters – Implements the IActionFilter attribute.
  3. Result filters – Implements the IResultFilter attribute.
  4. Exception filters – Implements the IExceptionFilter attribute.

Filters are executed in the order listed above. For example, authorization filters are always executed before action filters and exception filters are always executed after every other type of filter.

So, what we exeperience is:

  • in the Action filter (second one) we do start NHibernate session
  • in the Authorization filter (the very first one), we expect session to be in place

One solution is to start session in the OnAuthorize event...

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • thanks for your answer I didn't know about it. in somecontrollers I use Authorize atribute. so the better solution is putting session on the current context in onAuthorize event and ActionTransactionHelper class beginTransaction() method. – Hashem Aboonajmi Feb 12 '14 at 13:45
  • Yes, I do it this way, to be sure that the NH Session is ready for us anywhere... – Radim Köhler Feb 12 '14 at 14:02
  • would you check my another question: http://stackoverflow.com/questions/21738907/nhibernate-session-is-closed-when-refereshing-page – Hashem Aboonajmi Feb 12 '14 at 20:31
0

How I solved it:

public class AuthorizaAttributeWithSession : AuthorizeAttribute
{
    private readonly ISessionFactory _sessionFactory;

    public AuthorizaAttributeWithSession () : this(WebContainerManager.Get<ISessionFactory>())
    {
    }

    public AuthorizaAttributeWithSession(ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
    }
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var session = _sessionFactory.GetCurrentSession();
        if (session != null)
        {
            session.BeginTransaction();
        }
        base.OnAuthorization(filterContext);
    }
}

and my AdiminstratorAuthorize Filter:

public class AdministratorAuthorized : AuthorizaAttributeWithSession
{
    public AdministratorAuthorized()
    {
        Roles = "Administrators";
    }
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
    }
}
Hashem Aboonajmi
  • 13,077
  • 8
  • 66
  • 75
  • are you sure you haven't to implement the same exception filter that will close a session? For the chance of exception in authorize attribute – mazharenko Aug 28 '14 at 11:54