在hasbind MVC6 dnx451 NHibernate的的NullReferenceException [英] MVC6 dnx451 Nhibernate nullreferenceexception on hasbind

查看:442
本文介绍了在hasbind MVC6 dnx451 NHibernate的的NullReferenceException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用dnx451 moveing​​应用程序MVC 6。当试图在NHibernate中打开一个新的会话,我检查当前上下文时收到的NullReferenceException。我使用的是WebSessionContext(可以看出堆栈跟踪);但它看起来像上下文没有被成功地存储在HttpSession中。

是否NHibernate的curretly与MVC 6工作?我现在有它的MVC 5.工作最大的差异性是如何得到会话。由于MVC 6不使用的HttpModules,我提出了开幕式和关闭会话到过滤器的属性(我可以看到的唯一的缺点是,如果某些属性的教职员创下可能延迟加载除外)。

过滤器code是如下:

 公共类DbTransactionAttribute:ActionFilterAttribute
    {
        私人只读的IsolationLevel的IsolationLevel;        ///<总结>
        ///创建具有IsolationLevel.ReadUncommitted交易
        ///< /总结>
        公共DbTransactionAttribute(){
            的IsolationLevel = IsolationLevel.ReadUncommitted;
        }        公共DbTransactionAttribute(的IsolationLevel的IsolationLevel){
            this.isolationLevel =的IsolationLevel;
        }        公共覆盖无效OnActionExecuting(ActionExecutingContext filterContext){
            SessionManager.Instance.OpenSession();
            SessionManager.Instance.Session.BeginTransaction(的IsolationLevel);
        }        公共覆盖无效OnActionExecuted(ActionExecutedContext filterContext){
            ITransaction事务= SessionManager.Instance.Session.Transaction;
            如果(transaction.IsActive){
                如果(filterContext.Exception = NULL&放大器;!&安培; filterContext.ExceptionHandled)
                    transaction.Rollback();
                别的器transaction.commit();
            }
            transaction.Dispose();
            SessionManager.Instance.DisposeCurrentSession(); //我们已完成了会话
        }
}

启动mehod:

 公共无效配置(IApplicationBuilder应用程序,IHostingEnvironment ENV,ILoggerFactory的LoggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection(关键:记录));
            loggerFactory.AddDebug();            如果(env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            其他
            {
                app.UseExceptionHandler(errorHandlingPath:/首页/错误);
            }            app.UseIISPlatformHandler();            app.UseStaticFiles();            app.UseMvc(路线=>
            {
                routes.MapRoute(
                    名称:默认,
                    模板:{控制器= HOME} / {行动=指数} / {?ID});
            });
            Nhibernate.Context.BuildContext(ENV);
            Nhibernate.SessionManager.BuildSessionManager(ENV);
        }

上下文:

 类语境{
        私有静态Context实例;        私人ISessionFactory SessionFactory的;        内部ISessionFactory SessionFactory的{{返回SessionFactory的; }}        内部静态上下文实例{
            获得{
                如果(例如== NULL)初始化();
                返回实例;
            }
        }        内部静态无效BuildContext(Microsoft.AspNet.Hosting.IHostingEnvironment ENV){
            如果(例如== NULL)初始化();
        }        私有静态无效初始化(){
            例如=新的上下文();
            VAR hbrConfig =新NHibernate.Cfg.Configuration();
            var中的文件= typeof运算(上下文).Assembly.GetManifestResourceNames();
            hbrConfig.Configure(typeof运算(上下文).Assembly,
                资源名称:Ppn.Web.Nhibernate.hibernate.cfg.xml);
            hbrConfig.AddAssembly(typeof运算(ProposalNumber).Assembly);            instance.sessionFactory = hbrConfig.BuildSessionFactory();
        }
    }

该是SessionManager:

 公共类是SessionManager:ISessionManager {
        私有静态ISessionFactory SessionFactory的;        私有静态是SessionManager实例;        公共静态实例是SessionManager {
            获得{
                例如回报? (例如=新SessionManager(中间Context.Instance.SessionFactory));
            }
        }        公共静态无效BuildSessionManager(Microsoft.AspNet.Hosting.IHostingEnvironment ENV){
            如果(例如== NULL)实例=新SessionManager(中间Context.Instance.SessionFactory);
        }        公众是SessionManager(ISessionFactory SessionFactory的){
            SessionManager.sessionFactory = SessionFactory的;
        }        公众的Isession会议{
            获得{
                布尔hasBind = CurrentSessionContext.HasBind(SessionFactory的); //线失败
                ISession的结果;
                如果(hasBind)结果= SessionFactory.getCurrentSession()函数;
                否则结果=的openSession();
                返回结果;
                //返回CurrentSessionContext.HasBind(SessionFactory的)? SessionFactory.getCurrentSession()函数:的openSession();
            }
        }        公众的ISession的openSession(){
            ISession的会话= sessionFactory.OpenSession();
            CurrentSessionContext.Bind(会话);
            返回会议;
        }        公共无效DisposeCurrentSession(){
            如果(CurrentSessionContext.HasBind(SessionFactory的)){
                ISession的会话= CurrentSessionContext.Unbind(SessionFactory的);
                session.Close();
                session.Dispose();
            }
        }
    }

异常:

 的NullReferenceException:未将对象引用设置到对象的实例。    lambda_method(封闭,对象)
    NHibernate.Context.ReflectiveHttpContext.get_HttpContextCurrentItems()
    NHibernate.Context.WebSessionContext.GetMap()
    NHibernate.Context.MapBasedSessionContext.get_Session()
    NHibernate.Context.CurrentSessionContext.HasBind(ISessionFactory厂)
    Ppn.Web.Nhibernate.SessionManager.get_Session()在SessionManager.cs
                        布尔hasBind = CurrentSessionContext.HasBind(SessionFactory的);
    Ppn.Web.Controllers.ProposalNumberController.Index()在ProposalNumberController.cs
                    ISession的dbSession = SessionManager.Instance.Session;
    ---从previous位置堆栈跟踪,其中引发异常的结尾---


解决方案

我发现,我创建自定义的 ICurrentSessionContext 看起来像下面这样的解决方案:

  [Serializable接口]
公共类Mvc6SessionContext:MapBasedSessionContext {
    私人常量字符串SessionFactoryMapKey =NHibernate.Context.WebSessionContext.SessionFactoryMapKey;    公共Mvc6SessionContext(ISessionFactoryImplementor厂):基地(工厂){}    保护覆盖的IDictionary的GetMap(){
        返回Context.Instance.HttpContext.Items [SessionFactoryMapKey]作为IDictionary的;
    }    保护覆盖无效的setMap(IDictionary的值){
        Context.Instance.HttpContext.Items [SessionFactoryMapKey] =价值;
    }
}

我们还是娘家去的背景下,自定义访问。因此我刚修改过的上下文项为我的应用程序如下:

 类语境{
    私有静态Context实例;    私人ISessionFactory SessionFactory的;
    私有静态IHttpContextAccessor ​​contextAccessor;    内部ISessionFactory SessionFactory的{{返回SessionFactory的; }}    内部静态上下文实例{
        获得{
            如果(例如== NULL)初始化();
            返回实例;
        }
    }    内部的HttpContext的HttpContext {
        {返回contextAccessor.HttpContext; }
    }    内部静态无效BuildContext(IApplicationBuilder应用程序){
        如果(contextAccessor ​​== NULL)contextAccessor ​​= app.ApplicationServices.GetRequiredService< IHttpContextAccessor>();
        如果(例如== NULL)初始化();
    }    私有静态无效初始化(){
        例如=新的上下文();
        VAR hbrConfig =新NHibernate.Cfg.Configuration();
        var中的文件= typeof运算(上下文).Assembly.GetManifestResourceNames();
        hbrConfig.Configure(typeof运算(上下文).Assembly,
            资源名称:Ppn.Web.Nhibernate.hibernate.cfg.xml);
        hbrConfig.AddAssembly(typeof运算(ProposalNumber).Assembly);
        instance.sessionFactory = hbrConfig.BuildSessionFactory();
    }
}

和在启动我通过了 IApplicationBuilder

 公共无效配置(IApplicationBuilder应用程序,IHostingEnvironment ENV,ILoggerFactory的LoggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection(关键:记录));
        loggerFactory.AddDebug();        如果(env.IsDevelopment())
        {
            app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
        }
        其他
        {
            app.UseExceptionHandler(errorHandlingPath:/首页/错误);
        }        app.UseIISPlatformHandler();        app.UseStaticFiles();        app.UseMvc(路线=>
        {
            routes.MapRoute(
                名称:默认,
                模板:{控制器= HOME} / {行动=指数} / {?ID});
        });
        Nhibernate.Context.BuildContext(应用);
        Nhibernate.SessionManager.BuildSessionManager(ENV);
    }

最后一件事就是告诉NHibernate的使用我的执行在config文件:

 <属性名=current_session_context_class> Ppn.Web.Nhibernate.Mvc6SessionContext,Ppn.Web< /性>

整个THIG的symantics应该工作一样Nhibernate的使用标准的网键。我测试过,到目前为止那么好。

需要明确的是,这个项目是dnx451不是一个.NET的核心(不会的原因有很多工作)

I am moveing an application to MVC 6 using dnx451. When attempting to open a new session in nhibernate, I receive an NullReferenceException when checking the current context. I am using a WebSessionContext (as can be seen the stack trace); however it looks like the context is not being successfully stored in the HttpSession.

Does Nhibernate curretly work with MVC 6? I currently have it working in MVC 5. The big differnece is how I get sessions. Since MVC 6 does not use HttpModules, I have moved the opening and closing of sessions to a filter attribute (the only drawback I can see is a possible lazy loading exception if certain properties are hit in the veiw).

The filter code is as follows:

public class DbTransactionAttribute:ActionFilterAttribute
    {
        private readonly IsolationLevel isolationLevel;

        /// <summary>
        /// Creates a transaction with IsolationLevel.ReadUncommitted
        /// </summary>
        public DbTransactionAttribute() {
            isolationLevel = IsolationLevel.ReadUncommitted;
        }

        public DbTransactionAttribute(IsolationLevel isolationLevel) {
            this.isolationLevel = isolationLevel;
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext) {
            SessionManager.Instance.OpenSession();
            SessionManager.Instance.Session.BeginTransaction(isolationLevel);
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext) {
            ITransaction transaction = SessionManager.Instance.Session.Transaction;
            if (transaction.IsActive) {
                if (filterContext.Exception != null && filterContext.ExceptionHandled)
                    transaction.Rollback();
                else transaction.Commit();
            }
            transaction.Dispose();
            SessionManager.Instance.DisposeCurrentSession(); // We are finished with the session
        }
}

The Startup mehod:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection(key: "Logging"));
            loggerFactory.AddDebug();

            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler(errorHandlingPath: "/Home/Error");
            }

            app.UseIISPlatformHandler();

            app.UseStaticFiles();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
            Nhibernate.Context.BuildContext(env);
            Nhibernate.SessionManager.BuildSessionManager(env);
        }

The Context:

class Context {
        private static Context instance;

        private ISessionFactory sessionFactory;

        internal ISessionFactory SessionFactory { get { return sessionFactory; } }

        internal static Context Instance {
            get {
                if (instance == null) Initialize();
                return instance;
            }
        }

        internal static void BuildContext(Microsoft.AspNet.Hosting.IHostingEnvironment env) {
            if(instance == null) Initialize();
        }

        private static void Initialize() {
            instance = new Context();
            var hbrConfig = new NHibernate.Cfg.Configuration();
            var files = typeof(Context).Assembly.GetManifestResourceNames();
            hbrConfig.Configure(typeof(Context).Assembly, 
                resourceName: "Ppn.Web.Nhibernate.hibernate.cfg.xml");
            hbrConfig.AddAssembly(typeof(ProposalNumber).Assembly);

            instance.sessionFactory = hbrConfig.BuildSessionFactory();
        }
    }

The SessionManager:

public class SessionManager : ISessionManager {
        private static ISessionFactory sessionFactory;

        private static SessionManager instance;

        public static SessionManager Instance {
            get {
                return instance ?? (instance = new SessionManager(Context.Instance.SessionFactory));
            }
        }

        public static void BuildSessionManager(Microsoft.AspNet.Hosting.IHostingEnvironment env) {
            if (instance == null) instance = new SessionManager(Context.Instance.SessionFactory);
        }

        public SessionManager(ISessionFactory sessionFactory) {
            SessionManager.sessionFactory = sessionFactory;
        }

        public ISession Session {
            get {
                bool hasBind = CurrentSessionContext.HasBind(sessionFactory); //Line that fails
                ISession result;
                if (hasBind) result = sessionFactory.GetCurrentSession();
                else result = OpenSession();
                return result;
                //return CurrentSessionContext.HasBind(sessionFactory) ? sessionFactory.GetCurrentSession() : OpenSession();
            }
        }

        public ISession OpenSession() {
            ISession session = sessionFactory.OpenSession();
            CurrentSessionContext.Bind(session);
            return session;
        }

        public void DisposeCurrentSession() {
            if (CurrentSessionContext.HasBind(sessionFactory)) {
                ISession session = CurrentSessionContext.Unbind(sessionFactory);
                session.Close();
                session.Dispose();
            }
        }
    }

The Exception:

NullReferenceException: Object reference not set to an instance of an object.

    lambda_method(Closure , Object )
    NHibernate.Context.ReflectiveHttpContext.get_HttpContextCurrentItems()
    NHibernate.Context.WebSessionContext.GetMap()
    NHibernate.Context.MapBasedSessionContext.get_Session()
    NHibernate.Context.CurrentSessionContext.HasBind(ISessionFactory factory)
    Ppn.Web.Nhibernate.SessionManager.get_Session() in SessionManager.cs
                        bool hasBind = CurrentSessionContext.HasBind(sessionFactory);
    Ppn.Web.Controllers.ProposalNumberController.Index() in ProposalNumberController.cs
                    ISession dbSession = SessionManager.Instance.Session;
    --- End of stack trace from previous location where exception was thrown ---

解决方案

I've found a solution where I create a custom ICurrentSessionContext which looks like the following:

[Serializable]
public class Mvc6SessionContext: MapBasedSessionContext {
    private const string SessionFactoryMapKey = "NHibernate.Context.WebSessionContext.SessionFactoryMapKey";

    public Mvc6SessionContext(ISessionFactoryImplementor factory) : base(factory) {}

    protected override IDictionary GetMap() {
        return Context.Instance.HttpContext.Items[SessionFactoryMapKey] as IDictionary;
    }

    protected override void SetMap(IDictionary value) {
        Context.Instance.HttpContext.Items[SessionFactoryMapKey] = value;
    }
}

We still nee to get the custom access to the context. As such I just modified the the Context item for my app as follows:

class Context {
    private static Context instance;

    private ISessionFactory sessionFactory;
    private static IHttpContextAccessor contextAccessor;

    internal ISessionFactory SessionFactory { get { return sessionFactory; } }

    internal static Context Instance {
        get {
            if (instance == null) Initialize();
            return instance;
        }
    }

    internal HttpContext HttpContext {
        get { return contextAccessor.HttpContext; }
    }

    internal static void BuildContext(IApplicationBuilder app) {
        if(contextAccessor == null) contextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
        if (instance == null) Initialize();
    }

    private static void Initialize() {
        instance = new Context();
        var hbrConfig = new NHibernate.Cfg.Configuration();
        var files = typeof(Context).Assembly.GetManifestResourceNames();
        hbrConfig.Configure(typeof(Context).Assembly, 
            resourceName: "Ppn.Web.Nhibernate.hibernate.cfg.xml");
        hbrConfig.AddAssembly(typeof(ProposalNumber).Assembly);
        instance.sessionFactory = hbrConfig.BuildSessionFactory();
    }
}

And in the startup I pass the IApplicationBuilder

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection(key: "Logging"));
        loggerFactory.AddDebug();

        if (env.IsDevelopment())
        {
            app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler(errorHandlingPath: "/Home/Error");
        }

        app.UseIISPlatformHandler();

        app.UseStaticFiles();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
        Nhibernate.Context.BuildContext(app);
        Nhibernate.SessionManager.BuildSessionManager(env);
    }

Last thing is to tell Nhibernate to use my implementation in the config file:

<property name="current_session_context_class">Ppn.Web.Nhibernate.Mvc6SessionContext, Ppn.Web</property>

The symantics of the whole thig should work the same as the standard "web" key used in Nhibernate. I've tested and so far so good.

To be clear, this project is dnx451 not a .net core (which won't work for many reasons)

这篇关于在hasbind MVC6 dnx451 NHibernate的的NullReferenceException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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