Autofac、(流畅)nHibernate、ISession“会话已关闭!”间歇性地

发布于 2025-01-05 23:10:47 字数 3450 浏览 4 评论 0原文

我随机收到“会话已关闭!” Autofac 和 Fluent nHibernate 的以下配置错误:

Global.asax.cs:

builder.Register(x => new NHibernateConfigurator().GetSessionFactory()).SingleInstance();
builder.Register(x => x.Resolve<ISessionFactory>().OpenSession()).InstancePerHttpRequest();

NHibernateConfigurator.cs

    public class NHibernateConfigurator
{
    public Configuration Configure()
    {
        var configuration = new Configuration();
        configuration.SessionFactory()
            .Proxy.Through<ProxyFactoryFactory>()
            .Integrate.Using<Oracle10gDialect>();

        FluentConfiguration fluentConfiguration = Fluently.Configure(configuration);
        fluentConfiguration.Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserMap>());

        return fluentConfiguration.BuildConfiguration();
    }

    public ISessionFactory GetSessionFactory()
    {
        var configuration = Configure();
        return configuration.BuildSessionFactory();
    }
}

SomeController.cs:

private readonly IRepository repository;

public SomeController(IRepository repository)
{
this.repository = repository
}

[Transaction]
public ActionResult Index()
{
    var result = repository.GetUsers();
    return View(result);
}

TransactionAttribute.cs

public class TransactionAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        DependencyResolver.Current.GetService<ISession>().BeginTransaction(IsolationLevel.ReadCommitted);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ITransaction currentTransaction = DependencyResolver.Current.GetService<ISession>().Transaction;

        if (currentTransaction.IsActive)
        {
            if (filterContext.Exception != null && filterContext.ExceptionHandled)
            {
                currentTransaction.Rollback();
            }
        }
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        ITransaction currentTransaction = DependencyResolver.Current.GetService<ISession>().Transaction;

        base.OnResultExecuted(filterContext);
        try
        {
            if (currentTransaction.IsActive)
            {
                if (filterContext.Exception != null && !filterContext.ExceptionHandled)
                {
                    currentTransaction.Rollback();
                }
                else
                {
                    currentTransaction.Commit();
                }
            }
        }
        finally
        {
            currentTransaction.Dispose();
        }
    }
}

IRepository.cs:

public interface IRepository 
{
    IList<User> GetUsers();     
}

Repository.cs:

public class Repository : IRepository
{
    private readonly ISession session;

    public Repository(ISession session)
    {
        this.session = session;
    }

    public IList<User> GetUsers()
    {
        return session.QueryOver<User>().List();
    }
}

当前设置有效,但似乎间歇性失败(在少数页面重新加载或卡西尼号重新启动),GetUsers 抛出“会话已关闭!”错误。我认为在 InstancePerHttpRequest 上注册 ISessionFactory 可以避免这些问题。运气不好。有什么想法吗? nHibernate 和 Autofac 的新手,所以如果我未能发布足够的相关信息,请告诉我。

I'm having random "Session is closed!" errors with the following configuration of Autofac and Fluent nHibernate:

Global.asax.cs:

builder.Register(x => new NHibernateConfigurator().GetSessionFactory()).SingleInstance();
builder.Register(x => x.Resolve<ISessionFactory>().OpenSession()).InstancePerHttpRequest();

NHibernateConfigurator.cs

    public class NHibernateConfigurator
{
    public Configuration Configure()
    {
        var configuration = new Configuration();
        configuration.SessionFactory()
            .Proxy.Through<ProxyFactoryFactory>()
            .Integrate.Using<Oracle10gDialect>();

        FluentConfiguration fluentConfiguration = Fluently.Configure(configuration);
        fluentConfiguration.Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserMap>());

        return fluentConfiguration.BuildConfiguration();
    }

    public ISessionFactory GetSessionFactory()
    {
        var configuration = Configure();
        return configuration.BuildSessionFactory();
    }
}

SomeController.cs:

private readonly IRepository repository;

public SomeController(IRepository repository)
{
this.repository = repository
}

[Transaction]
public ActionResult Index()
{
    var result = repository.GetUsers();
    return View(result);
}

TransactionAttribute.cs

public class TransactionAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        DependencyResolver.Current.GetService<ISession>().BeginTransaction(IsolationLevel.ReadCommitted);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        ITransaction currentTransaction = DependencyResolver.Current.GetService<ISession>().Transaction;

        if (currentTransaction.IsActive)
        {
            if (filterContext.Exception != null && filterContext.ExceptionHandled)
            {
                currentTransaction.Rollback();
            }
        }
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        ITransaction currentTransaction = DependencyResolver.Current.GetService<ISession>().Transaction;

        base.OnResultExecuted(filterContext);
        try
        {
            if (currentTransaction.IsActive)
            {
                if (filterContext.Exception != null && !filterContext.ExceptionHandled)
                {
                    currentTransaction.Rollback();
                }
                else
                {
                    currentTransaction.Commit();
                }
            }
        }
        finally
        {
            currentTransaction.Dispose();
        }
    }
}

IRepository.cs:

public interface IRepository 
{
    IList<User> GetUsers();     
}

Repository.cs:

public class Repository : IRepository
{
    private readonly ISession session;

    public Repository(ISession session)
    {
        this.session = session;
    }

    public IList<User> GetUsers()
    {
        return session.QueryOver<User>().List();
    }
}

This current set-up works, but seems to fail intermittently (after a few page reloads or restarts of Cassini) with GetUsers throwing "Session is closed!" errors. I thought registering the ISessionFactory on an InstancePerHttpRequest would avoid these issues. No luck. Any ideas? New to nHibernate and Autofac, so if I failed to post enough relevant information, let me know.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

寂寞美少年 2025-01-12 23:10:47

看来我的配置对于我的自定义成员资格提供程序和自定义角色提供程序之外的任何 nHibernate 调用都完美工作 - 据我所知,它们是问题所在,这意味着这个问题并没有真正解决问题。

It appears my configuration is working perfectly for any nHibernate calls outside of my custom membership providers and custom role providers - they are the issue as far as I can tell, which means this question isn't really addressing the issue.

八巷 2025-01-12 23:10:47

您的存储库是如何注册的?是 InstancePerHttpRequest (应该是),还是 Singleton (它不应该)。

How is your Repository registered? Is it InstancePerHttpRequest (which is should be), or Singleton (which it shouldn't).

寻找一个思念的角度 2025-01-12 23:10:47

我在使用 MVC 3 操作过滤器时遇到了类似的问题,似乎它们在 MVC 3 中缓存得非常积极,并且发现会话并不总是打开,因为 OnActionExecuted 并不总是触发。

将会话移动到控制器构造函数中,如下所示:

 public SomeController(
        ISession session,
        ILogger logger,
        IRepository<Something> someRepository )
    {
        _session = session;
        _logger = logger;
        _someRepository = someRepository;
    }

在要包装事务的操作中:

using (var transaction = _session.BeginTransaction())
{
   // do something with your repository
   _someRepository.Add(new Something());
   transaction.commit();
}

I have had a similar problem using MVC 3 action filters and seems they are cached quite aggressively in MVC 3 and found that sessions were not always being opened as OnActionExecuted not always fire.

Move your session into the controller constructor like so:

 public SomeController(
        ISession session,
        ILogger logger,
        IRepository<Something> someRepository )
    {
        _session = session;
        _logger = logger;
        _someRepository = someRepository;
    }

In your action where you want to wrap a transaction:

using (var transaction = _session.BeginTransaction())
{
   // do something with your repository
   _someRepository.Add(new Something());
   transaction.commit();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文