Using NHibernate Interceptor with Ninject to Retrieve a Registered User

I read this article and found it quite interesting (thanks @Aaronaught). Closest to solve my problem.

The only detail is that in my case I would use the NHibernate interceptor, but the exception is thrown An unhandled exception of type 'System.StackOverflowException' occurred in System.Core.dll

code

Factory Session:

 public class SessionFactoryBuilder : IProvider { private ISessionFactory _sessionFactory; private readonly Configuration _configuration; public SessionFactoryBuilder(AuditInterceptor auditInterceptor) { _configuration = Fluently.Configure(new Configuration().Configure()) .Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<IEntidade>(new AutomappingConfiguration()))) .ExposeConfiguration(SetupDatabase) .BuildConfiguration(); _configuration.SetInterceptor(auditInterceptor); _sessionFactory = _configuration.BuildSessionFactory(); } private static void SetupDatabase(Configuration config) { var schema = new SchemaExport(config); //schema.Execute(true, true, false); } public object Create(IContext context) { return _sessionFactory; } public Type Type { get { return typeof(ISessionFactory); } } } 

I have a module that installs my repositories and ORM (NHibernate)

 public class RepositoriosModule : NinjectModule { public override void Load() { Bind<AuditInterceptor>().ToSelf().InRequestScope(); // NHibernate Bind<ISessionFactory>().ToProvider<SessionFactoryBuilder>().InSingletonScope(); Bind<ISession>().ToMethod(CreateSession).InRequestScope(); Bind<NHUnitOfWork>().ToSelf().InRequestScope(); //Model Repositories Bind<IRepositorio<Usuario>, IUsuariosRepositorio>().To<UsuariosRepositorio>().InRequestScope(); } private ISession CreateSession(IContext context) { return context.Kernel.Get<ISessionFactory>().OpenSession(); } } 

Interceptor for updating checked properties ( CriadoEm (create at), CriadoPor (create by), AtualizadoEm and AtualizadoPor )

 public class AuditInterceptor : EmptyInterceptor { private readonly IUsuario _usuarioLogado; public AuditInterceptor(IUsuario usuarioLogado) { _usuarioLogado = usuarioLogado; } public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, NHibernate.Type.IType[] types) { var auditableObject = entity as IAuditavel; if (auditableObject != null) { currentState[Array.IndexOf(propertyNames, "AtualizadoEm")] = DateTime.Now; return true; } return false; } public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, NHibernate.Type.IType[] types) { var auditableObject = entity as IAuditavel; if (auditableObject != null) { var currentDate = DateTime.Now; state[Array.IndexOf(propertyNames, "CriadoEm")] = currentDate; return true; } return false; } } 

Provider to retrieve a registered user:

public class UsuarioProvider: provider {private Usuario _usuario;

 protected override Usuario CreateInstance(IContext context) { var usuariosRepositorio = context.Kernel.Get<IUsuariosRepositorio>(); // Stackoverflow on this line!! if (_usuario == null && WebSecurity.IsAuthenticated) _usuario = usuariosRepositorio.Get(WebSecurity.CurrentUserId); return _usuario; } 

}

And the NinjectWebCommon class (web application) defines:

 private static void RegisterServices(IKernel kernel) { kernel.Bind<IUsuario>().ToProvider<UsuarioProvider>().InRequestScope(); //.When((req) => WebSecurity.IsAuthenticated) kernel.Load(new RepositoriosModule(), new MvcSiteMapProviderModule()); } 

[Add] Repository class

 public class UsuariosRepositorio : Repositorio<Usuario>, IUsuariosRepositorio { public UsuariosRepositorio(NHUnitOfWork unitOfWork) : base(unitOfWork) { } } public class Repositorio<T> : IRepositorio<T> where T : class, IEntidade { private readonly NHUnitOfWork _unitOfWork; public IUnitOfWork UnitOfWork { get { return _unitOfWork; } } private readonly ISession _session; public Repositorio(IUnitOfWork unitOfWork) { _unitOfWork = (NHUnitOfWork)unitOfWork; _session = _unitOfWork.Context.SessionFactory.GetCurrentSession(); } public void Remover(T obj) { _session.Delete(obj); } public void Armazenar(T obj) { _session.SaveOrUpdate(obj); } public IQueryable<T> All() { return _session.Query<T>(); } public object Get(Type entity, int id) { return _session.Get(entity, id); } public T Get(Expression<Func<T, bool>> expression) { return Query(expression).SingleOrDefault(); } public T Get(int id) { return _session.Get<T>(id); } public IQueryable<T> Query(Expression<Func<T, bool>> expression) { return All().Where(expression); } } 

Problem

The problem occurs in the UsuarioProvider class when trying to get the user repository.

Stackoverflow error:

An unhandled exception of type 'System.StackOverflowException' occurred in System.Core.dll

+1
source share
1 answer

I see two problems:

The main problem I see is that SessionFactoryBuilder requires an AuditInterceptor , which requires IUsuario , which requires a UsuarioProvider , which requires a SessionFactoryBuilder , thereby introducing a loop and stack overflow.

The second problem that I see is that your AuditInterceptor is associated with the request when your SessionFactoryBuilder is single-user. I must admit, I do not see how it works with several registered users.

You should create an instance of AuditInterceptor as part of CreateSession , and not try to create it once and for all as part of the session creator. Once this is done, your interceptor should not rely on a session that needs an AuditInterceptor as part of its creation (this may require a separate session creation mechanism. A stateless session can do the trick)

+2
source

Source: https://habr.com/ru/post/1389240/


All Articles