Autofac,(流利)nHibernate,ISession“会议闭幕!”间歇

时间:2012-02-14 09:16:24

标签: asp.net-mvc nhibernate dependency-injection fluent-nhibernate autofac

我随机“会话已关闭!”使用以下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();
    }
}

此当前设置有效,但似乎间歇性地失败(在几页重新加载或重新启动Cassini之后),GetUsers抛出“Session is closed!”错误。我认为在InstancePerHttpRequest上注册ISessionFactory可以避免这些问题。没运气。有任何想法吗? nHibernate和Autofac的新手,所以如果我没有发布足够的相关信息,请告诉我。

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我在使用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();
}