0

ISessionPerWebRequestベースで自分のを解決するようにMVCプロジェクトを設定しています。

これが私がこれまでに持っているものです:

Castle WindsorセットアップでISession、ファクトリメソッドを使用して登録します。

Component.For<ISession>().UsingFactoryMethod(ctx => MsSql2008SessionFactory.OpenSession()).LifestylePerWebRequest()

私の場合、リクエストが始まるたびにNHibernateGlobal.asax Application_Start()にバインドします。ISessionCurrentSessionContext

BeginRequest += delegate{
            CurrentSessionContext.Bind(
                     MsSql2008SessionFactory.OpenSession());
                       };

EndRequest += delegate{
             var session = MsSql2008SessionFactory
                             .SessionFactory
                               .GetCurrentSession();
              if (session != null)
              {
                session.Dispose();
              }
             CurrentSessionContext
                     .Unbind(MsSql2008SessionFactory
                         .SessionFactory);
        };

初めてページにリクエストを送信すると、すべて正常に機能します。2回目にページにリクエストを送信すると、次のような例外が発生します。

セッションは終了しました!オブジェクト名:'ISession'。

私は何を正しくやっていないのですか?

4

2 に答える 2

2

これは私があなたのために物事がうまくいくかもしれない方法です。一部の構成がうまくいかない場合に備えて、FluentNhibernateを使用します。

public interface INHibernateSessionFactoryHelper
{
    ISessionFactory CreateSessionFactory();
}


public class NhibernateSessionFactoryHelper
{
    private static readonly string ConnectionString =
        ConfigurationManager.ConnectionStrings["SqlConnectionString"].ToString();

    public static ISessionFactory CreateSessionFactory()
    {
        return Fluently.Configure()
            .ProxyFactoryFactory("NHibernate.Bytecode.DefaultProxyFactoryFactory, NHibernate")
            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<EntityMap>())
            .Database(
                MsSqlConfiguration.MsSql2008.ConnectionString(ConnectionString).AdoNetBatchSize(1000))
            .Cache(
                c =>
                c.ProviderClass<SysCacheProvider>().UseSecondLevelCache().UseQueryCache().UseMinimalPuts())
            .ExposeConfiguration(c => c.SetProperty(Environment.GenerateStatistics, "true")
                                          .SetProperty(Environment.SessionFactoryName, "My Session Factory")
                                          .SetProperty(Environment.CurrentSessionContextClass, "web"))
            .Diagnostics(d => d.Enable().OutputToFile(@"c:\temp\diags.txt"))
            .BuildSessionFactory();
    }
}

次に、私のWindsorインストーラーは次のようになります

public class NHibernateInstaller:IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<ISessionFactory>().Instance(NhibernateSessionFactoryHelper.CreateSessionFactory()));
        container.Register(Component.For<ISessionManager>().ImplementedBy<SessionManager>().LifestylePerWebRequest());
    }
}

使用しているSessionManagerのコードを省略しました。ご希望の場合はお知らせください

UPDTAE:セッションとトランザクションの管理に使用するコードは次のとおりです(インターネット上に散在しているものを見つけましたが、あまり変更しなくてもすべてうまく機能しました。ISessionManagerは前の例に従って配線され、サービスの構成者に挿入されています。

public interface ISessionManager : IDisposable
{
    ISession Session { get; set; }
    ISession GetSession();
}

public class SessionManager : ISessionManager
{
    private readonly ISessionFactory _sessionFactory;
    private TransactionScope _scope;
    public SessionManager(ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
    }

    #region ISessionManager Members

    public ISession Session { get; set; }

    public ISession GetSession()
    {
        if (Session == null)
        {
            Session = _sessionFactory.OpenSession();
            if (!CurrentSessionContext.HasBind(_sessionFactory))
            {
                _scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions {IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted});
                Session.BeginTransaction(IsolationLevel.ReadCommitted);
                CurrentSessionContext.Bind(Session);
            }
        }

        Session = _sessionFactory.GetCurrentSession();
        Session.FlushMode = FlushMode.Never;
        return Session;
    }


    public void Dispose()
    {
        if (CurrentSessionContext.HasBind(_sessionFactory))
        {
            CurrentSessionContext.Unbind(_sessionFactory);
        }
        try
        {
            Session.Transaction.Commit();
            _scope.Complete();
            _scope.Dispose();
            Session.Flush();
        }
        catch (Exception)
        {
            if (Session.Transaction != null && Session.Transaction.IsActive)
            {
                Session.Transaction.Rollback();
            }
            throw;
        }
        finally
        {
            Session.Close();
            Session.Dispose();
        }
    }

    #endregion
}

コンストラクターの例:

private readonly ISessionManager _sessionManager;
private readonly ISession _session;
 public UserService(ISessionManager sessionManager)
    {

        _sessionManager = sessionManager;
        _session = sessionManager.GetSession();

     }
于 2012-05-06T03:13:44.837 に答える
2

これに対する答えは非常に単純であることが判明しました。

私が注入ISessionしていたリポジトリにはSingletonライフスタイルがありました。

これはISession、最初のリクエストで挿入されたものが後続のリクエストにも使用されていたため(私のリポジトリクラスはアプリケーションの開始時にのみ作成されていたため)、すでに破棄されていることを意味します。

于 2012-05-12T12:35:26.850 に答える