一起使用NHibernate拦截与Ninject来获取登录的用户 [英] Using NHibernate interceptor together with Ninject to retrieve the logged in user
问题描述
我读<一个href=\"http://stackoverflow.com/questions/7090636/ninject-nhibernate-and-auditing-in-asp-net-mvc\">this文章,并发现它很有趣(感谢@Aaronaught)。什么是最接近于解决我的问题。
唯一的细节是,在我的情况我会使用NHibernate的拦截器,但会抛出异常类型'System.StackOverflowException'发生在System.Core.dll未处理的异常
code
会话工厂:
公共类SessionFactoryBuilder:IProvider
{
私人ISessionFactory _sessionFactory;
私人只读配置_configuration; 公共SessionFactoryBuilder(AuditInterceptor auditInterceptor)
{
_configuration = Fluently.Configure(新配置()。配置())
.Mappings(M =&GT; m.AutoMappings.Add(AutoMap.AssemblyOf&所述; IEntidade&GT;(新AutomappingConfiguration())))
.ExposeConfiguration(SetupDatabase)
.BuildConfiguration(); _configuration.SetInterceptor(auditInterceptor); _sessionFactory = _configuration.BuildSessionFactory();
} 私有静态无效SetupDatabase(配置配置)
{
VAR模式=新的SchemaExport(配置);
//schema.Execute(true,真,假);
} 公共对象创建(IContext上下文)
{
返回_sessionFactory;
} 公共类型类型
{
得到{typeof运算(ISessionFactory); }
}
}
我有设置我的资料库和模块ORM(NHibernate的)
公共类RepositoriosModule:NinjectModule
{
公共覆盖无效负载()
{
绑定&LT; AuditInterceptor&GT;()ToSelf()InRequestScope()。 // NHibernate的
绑定&LT; ISessionFactory&GT;()ToProvider&LT; SessionFactoryBuilder&GT;()InSingletonScope()。
绑定&LT;&ISession的GT;()ToMethod(了createSession).InRequestScope()。
绑定&LT; NHUnitOfWork&GT;()ToSelf()InRequestScope()。 //模型库
绑定&所述; IRepositorio&下; Usuario&gt;中IUsuariosRepositorio方式&gt;()到&lt; UsuariosRepositorio方式&gt;()InRequestScope();
} 私人的ISession了createSession(IContext上下文)
{
返回context.Kernel.Get&所述; ISessionFactory方式&gt;()的openSession();
}
}
拦截器来更新可审计性( CriadoEm
(创建于), CriadoPor
(由创建), AtualizadoEm
和 AtualizadoPor
)
公共类AuditInterceptor:EmptyInterceptor
{
私人只读IUsuario _usuarioLogado;
公共AuditInterceptor(IUsuario usuarioLogado)
{
_usuarioLogado = usuarioLogado;
} 公众覆盖布尔OnFlushDirty(对象实体,对象ID,对象[] currentState的,对象[] previousState,字符串[] propertyNames,NHibernate.Type.IType []类型)
{
VAR auditableObject =实体IAuditavel;
如果(auditableObject!= NULL)
{
currentState的[Array.IndexOf(propertyNamesAtualizadoEm)] = DateTime.Now;
返回true;
}
返回false;
} 公众覆盖布尔的OnSave(对象实体,对象ID,对象[]状态,字符串[] propertyNames,NHibernate.Type.IType []类型)
{
VAR auditableObject =实体IAuditavel;
如果(auditableObject!= NULL)
{
VAR的currentdate = DateTime.Now;
状态[Array.IndexOf(propertyNames,CriadoEm)] =的currentdate;
返回true;
}
返回false;
}
}
一个供应商来获取登录的用户:
公共类UsuarioProvider:提供
{
私人Usuario _usuario;
保护覆盖Usuario的CreateInstance(IContext上下文)
{
VAR usuariosRepositorio = context.Kernel.Get&LT; IUsuariosRepositorio&GT;(); //#1在此行! 如果(_usuario == NULL和放大器;&安培; WebSecurity.IsAuthenticated)
_usuario = usuariosRepositorio.Get(WebSecurity.CurrentUserId);
返回_usuario;
}
}
和类 NinjectWebCommon
(Web应用程序)定义:
私有静态无效RegisterServices(内核的iKernel)
{
kernel.Bind&LT; IUsuario&GT;()ToProvider&LT; UsuarioProvider&GT;()InRequestScope()。 //.When((req)= GT; WebSecurity.IsAuthenticated)
kernel.Load(新RepositoriosModule(),新MvcSiteMapProviderModule());
}
[添加]仓储类
公共类UsuariosRepositorio:Repositorio&LT; Usuario&gt;中IUsuariosRepositorio
{
公共UsuariosRepositorio(NHUnitOfWork的UnitOfWork)
:基地(的UnitOfWork)
{}
}
公共类Repositorio&LT; T&GT; :IRepositorio&LT; T&GT;
其中T:类,IEntidade
{ 私人只读NHUnitOfWork _unitOfWork;
公共IUnitOfWork的UnitOfWork {{返回_unitOfWork; }}
私人只读的Isession _session; 公共Repositorio(IUnitOfWork的UnitOfWork)
{
_unitOfWork =(NHUnitOfWork)的UnitOfWork;
_session = _unitOfWork.Context.SessionFactory.GetCurrentSession();
} 公共无效卸妆(T OBJ)
{
_session.Delete(OBJ);
} 公共无效Armazenar(T OBJ)
{
_session.SaveOrUpdate(OBJ);
} 公众的IQueryable&LT; T&GT;所有()
{
返回_session.Query&LT; T&GT;();
} 公共对象获取(Type实体,INT ID)
{
返回_session.Get(实体ID);
} 公共吨得到(前pression&LT;&Func键LT; T,BOOL&GT;&GT;前pression)
{
返回查询(如pression).SingleOrDefault();
} 公共吨得到(INT ID)
{
返回_session.Get&LT; T&GT;(ID);
} 公众的IQueryable&LT; T&GT;查询(前pression&LT;&Func键LT; T,BOOL&GT;&GT;前pression)
{
返回所有(),其中(EX pression)。
}
}
问题
在类中发生的问题 UsuarioProvider
试图获取用户信息库。
错误#1:
类型'System.StackOverflowException的未处理的异常出现在System.Core.dll
块引用>解决方案我看到两个问题:
我看到的主要问题是,
SessionFactoryBuilder
需要一个AuditInterceptor
这需要一个IUsuario
,这需要一个UsuarioProvider
,这需要一个SessionFactoryBuilder
,从而引入一个周期,堆栈溢出。我看到的第二个问题是,你的
AuditInterceptor
链接到一个请求时,你的SessionFactoryBuilder
是单身等等。我必须承认,我看不出它如何与多个用户的登录工作。您应该实例,并附加
AuditInterceptor
作为一部分了createSession
,而不是试图一次创建它,所有的会话建设者的一部分。一旦做到这一点,你的拦截器不应该依赖一个需要AuditInterceptor作为其创作的一部分,一个会话(您可能需要一个单独的会话建立机制这一点。一个无状态的会话可能会做的伎俩)I was reading this article and found it quite interesting (thanks @Aaronaught). Was what came closest to solve my problem.
The only detail is that in my case I would use the NHibernate interceptor, but an exception is thrown
An unhandled exception of type 'System.StackOverflowException' occurred in System.Core.dll
Code
Session factory:
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 sets up 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 to update auditable properties (
CriadoEm
(create at),CriadoPor
(create by),AtualizadoEm
andAtualizadoPor
)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; } }
A provider to retrieve the logged in 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 class
NinjectWebCommon
(web application) define: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 class
UsuarioProvider
while trying to retrieve the user repository.Stackoverflow error:
An unhandled exception of type 'System.StackOverflowException' occurred in System.Core.dll
解决方案I see two problems :
The main problem I see is that
SessionFactoryBuilder
needs anAuditInterceptor
which needs anIUsuario
, which needs aUsuarioProvider
, which needs aSessionFactoryBuilder
, thus introducing a cycle, and a stack-overflow.The second problem I see is that your
AuditInterceptor
is linked to a request when yourSessionFactoryBuilder
is singleton like. I must confess I can't see how it work with several logged users.You should instantiate and attach the
AuditInterceptor
as part of theCreateSession
, instead of trying to create it once and for all as part of the Session builder. Once this is done, your interceptor should not rely on a Session that needs an AuditInterceptor as part of its creation (you may need a separate Session creation mechanism for that. A stateless Session might do the trick)这篇关于一起使用NHibernate拦截与Ninject来获取登录的用户的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!