我正在使用dnx451将一个应用程序迁移到MVC 6。当尝试在nhibernate中打开一个新会话时,我在检查当前上下文时会收到一个NullReferenceException。我使用的是一个WebSessionContext (可以看到堆栈跟踪);但是,看起来上下文没有成功地存储在HttpSession中。
Nhibernate是否与MVC 6一起工作?我现在让它在MVC 5中工作,最大的不同是我如何获得会话。因为MVC 6不使用HttpModules,所以我已经将会话的开始和结束移到了一个筛选器属性(如果某些属性在veiw中被击中,我能看到的唯一缺点是一个可能的延迟加载异常)。
过滤器代码如下:
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
}
}启动方法:
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);
}背景:
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();
}
}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();
}
}
}例外情况:
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 ---发布于 2016-02-22 22:08:55
我找到了一个解决方案,其中我创建了一个自定义ICurrentSessionContext,如下所示:
[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;
}
}我们仍然需要获得对上下文的自定义访问。因此,我修改了我的应用程序的上下文项,如下所示:
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();
}
}在启动过程中我通过了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);
}最后一件事是告诉Nhibernate在配置文件中使用我的实现:
<property name="current_session_context_class">Ppn.Web.Nhibernate.Mvc6SessionContext, Ppn.Web</property>整个thig的系统应该与Nhibernate中使用的标准"web“键一样工作。我已经测试过了,到目前为止还不错。
要明确的是,这个项目是dnx451,而不是.net核心(由于许多原因,它不能工作)
发布于 2016-02-20 09:18:27
这告诉我,NHibernate正在使用反射来访问属性。Asp.Net.Core是一种主要的重写,有很多变化,因此在Asp.Net核心和以前的版本之间没有确切的二进制/API/函数奇偶。因此,使用以前版本的Asp.Net设计的许多项目将无法使用Asp.Net.Core。
https://stackoverflow.com/questions/35440413
复制相似问题