Search code examples
c#nhibernatepostsharp

How to get current NHibernate session for using Transaction attribute using PostSharp AOP?


I want to get current NHibernate Session for using the Transaction attribute using PostSharp AOP.

Instead of below,

public void Create<TEntity>(TEntity entity) where TEntity : class, IIdentity
{
    var session = SessionFactory.CurrentSession;

    using (ITransaction transaction = session.BeginTransaction())
    {
        try
    { 
        session.Save(entity);
            transaction.Commit(); 
        } 
        catch {
            transaction.Rollback();
            throw;
        }
    }
}

I want to use like this,

[NHibernateTransaction]
public void Create<TEntity>(TEntity entity) where TEntity : class, IIdentity   
{       
    session.Save(entity);
}

Solution

  • In the "Consuming Dependencies" section of the PostSharp documentation you can find descriptions and examples for different approaches of injecting dependencies into aspects.

    One common approach is to let the dependency injection container initialize the dependencies of the existing aspect's instance. You can do this from the RuntimeInitialize method of the aspect. For example, with StructureMap container:

    [Serializable]
    public class NHibernateTransactionAttribute : OnMethodBoundaryAspect
    {
        public ISessionFactory SessionFactory { get; set; }
    
        public override void RuntimeInitialize(MethodBase method)
        {
            // Initialize the SessionFactory according to the container configuration.
            ObjectFactory.BuildUp(this);
        }
    
        // ...
    }
    

    Another solution is to use the DI container as the global service locator inside your aspect - just ask the container to retrieve a required instance for you. As an optimization, you may also want to store the session in the MethodExecutionArgs.MethodExecutionTag property inside the OnEntry method and retrieve it inside the OnSuccess and OnException methods.

    public override void OnEntry(MethodExecutionArgs args)
    {
        ISessionFactory sessionFactory = ObjectFactory.GetInstance<ISessionFactory>();
        var session = SessionFactory.CurrentSession;
        // Store the session in the method context.
        args.MethodExecutionTag = session;
        // ...
    }
    
    public override void OnSuccess(MethodExecutionArgs args)
    {
        // Retrieve the session from the method context.
        var session = (ISession) args.MethodExecutionTag;
        // ...
    }
    

    With the Professional Edition of PostSharp you can also import the properties and methods of the target class into the aspect. So, if your class has a SessionFactory property, you can import and use it inside your aspect. Note, that you also need to implement IInstanceScopedAspect in this case.

    [Serializable]
    public class NHibernateTransactionAttribute : OnMethodBoundaryAspect, IInstanceScopedAspect
    {
        [ImportMember("SessionFactory", IsRequired = true)] 
        public Property<ISessionFactory> SessionFactoryProperty;
    
        public override void OnEntry(MethodExecutionArgs args)
        {
            var session = this.SessionFactoryProperty.Get().CurrentSession;
            // ...
        }
    
        object IInstanceScopedAspect.CreateInstance(AdviceArgs adviceArgs)
        {
            return this.MemberwiseClone();
        }
    
        void IInstanceScopedAspect.RuntimeInitializeInstance()
        {
        }
    
        // ...
    }