2012-05-05 5 views
0

MVCプロジェクトを設定して、PerWebRequestベースでISessionを解決します。キャッスルウィンザーLifestylePerWebRequest - 最初のウェブリクエストでは、セッションの最初のウェブで解決されるようです

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

私はファクトリメソッド使用して、私のISessionを登録し、私の城ウィンザーのセットアップでは:私のGlobal.asaxApplication_Start()

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

を私はNHibernateののCurrentSessionContextそれぞれに自分のISessionをバインドリクエストが始まる時刻:

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

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

初めてページにリクエストすると、すべて正常に動作します。 ページに2回目のリクエストを行うと、例外が発生します。

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

正しくは何をしていませんか?

+0

あなたが配線するWindsorInstallerを使用する必要があり、このすべてアップBeginRequestイベントとEndRequestのは、同じスレッドで扱うときに注意することは、トランザクションに包まれるべきNHibernateので –

+0

CurrentSessionContextを使用します。あなたの手の届かないものは、バインド前にすでにバインドされているかどうかを確認しないでください。 –

+0

だけでなく、すべてのいずれかを実行することが保証されていない –

答えて

2

これに対する答えは非常に簡単であることが判明し

ISessionに私が注射したリポジトリには、Singletonのライフスタイルがありました。

これは、最初のリクエストで注入されたISessionがサブミットリクエストにも使用されていたことを意味していました(私のリポジトリクラスはアプリケーションの開始時に作成されただけなので)。

2

これは私があなたのために働く方法です。私は、Fluent Nhibernateを使用しています。

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(); 
    } 
} 

その後、私のウィンザーのインストーラは、私が使用しSessionManagerのためのコードを省略している。この

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()); 
    } 
} 

のように見えます。

UPDTAE:これはセッションやトランザクションを管理するためのコードです(私はこれについてインターネットに散在していますが、あまり変更を加えることなくすべてうまく機能していました)。私の前の例と私のサービスのconstuctorにして注入さ

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(); 

    } 
+1

セッションファクトリもシングルトンである必要があります。 –

+0

ありがとう@コードジャーム。これは私がすでに持っているものです。ビュー内でIEnumerableまたはIQueryableアイテムを利用するときに、セッションが開いたままになっていることをどのように確認していますか?それが私が解決しようとしている主な問題です。 –

+0

私はViewModelsを使用します。私のビューでは、IEnumerableまたはIQueryableがデータレイヤーから返されることはありません。これはViewModelsのために設計されたものです。私は「サービス」のアプローチを使って言います。例:IProdutServiceはWindsorに接続され、Productsコントローラのコンストラクタに挿入されます。セッションが開いている限り。私は何の問題に遭遇していない。私はあなたのためにこの問題を引き起こす何かがあると思う。 –

関連する問題