一起使用NHibernate拦截与Ninject来获取登录的用户 [英] Using NHibernate interceptor together with Ninject to retrieve the logged in user

查看:196
本文介绍了一起使用NHibernate拦截与Ninject来获取登录的用户的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读<一个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 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;
    }
}

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 an AuditInterceptor which needs an IUsuario, which needs a UsuarioProvider, which needs a SessionFactoryBuilder, thus introducing a cycle, and a stack-overflow.

The second problem I see is that your AuditInterceptor is linked to a request when your SessionFactoryBuilder 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 the CreateSession, 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆