2011-02-01 85 views
11

我想在我的WCF應用程序中實現一個session-per-request模型,並且已經閱讀了關於此主題的無數文檔,但看起來好像沒有完成這個示範。事實上,我遇到了一些非常有用的物品來到像這樣的:WCF,NHibernate和Ninject的session-per-request實現

NHibernate's ISession, scoped for a single WCF-call

,但這些都是從舊日子NHibernate和Ninject沒有WCF具體實現,因此他們取得了什麼,我需要通過實施他們的自定義服務提供商等等。既然Ninject和NHibernate現在都有WCF支持,我想通過使用它們的模塊使事情保持一致,但我最終在這裏...

基本設置和流程應如下所示:

  1. 設置CurrentSessionContext到WcfOperationSessionContext在NHibernate的配置
  2. 在服務啓動,開始請求,或周圍的初始化時間,任何地點,公開會議並將其綁定到當前上下文
  3. 庫得到使用SessionFactory.GetCurrentSession當前會話實例()方法
  4. 取消綁定,並在生命週期

我最初的問題是年底結束會話,我是不是能夠訪問到WCF的生命週期來處理我的綁定。在深入挖掘ninject代碼之後,我設法將我的方法綁定到ServiceHost的Opening/Closing事件上,但沒有多少變化,但之後我無法訪問OperationContext,因爲它是線程靜態的。

後來我嘗試啓用asp.net兼容性並使用Application_BeginRequest和Application_EndRequest,它看起來很有希望,但我不認爲這是最好的解決方案,因爲我應該將東西綁定到服務實例,而不是http請求。

有沒有人使用ninject的內置wcf擴展庫實現了這一點?或者我可能做錯什麼想法?

回答

2

我已在IDispatchMessageInspector的幫助下按請求會話生命週期實施。 也許你可以實現Ninject的自定義生命期管理器來實現每個Web請求。

+0

您是對的,謝謝。我在讀有關IDispatchMessageInspector,我發現這個實現: https://igloocoder.net:8443/svn/IglooCommons/trunk/src/IglooCoder.Commons/WcfNhibernate/ 有了一些小的調整,我能夠使它工作。 – salimaabey 2011-02-02 15:13:00

1

海蘭

你可以做到以下幾點:

public class DomainModule : NinjectModule 
{ 
    private const string RealSessionIndicator = "RealSession"; 

    private readonly ProxyGenerator proxyGenerator = new ProxyGenerator(); 

    public override void Load() 
    { 
     this.Bind<ISession>().ToMethod(ctx => ctx.Kernel.Get<ISessionFactory>().OpenSession()) 
      .When(r => r.Parameters.Any(p => p.Name == RealSessionIndicator)) 
      .InRequestScope(); 

     this.Bind<Func<ISession>>().ToMethod(ctx =>() => ctx.Kernel.Get<ISession>(new Parameter(RealSessionIndicator, (object)null, true))); 

     this.Bind<ISession>() 
      .ToMethod(this.CreateSessionProxy) 
      .InTransientScope(); 

     this.Bind<ISessionFactory>().ToMethod(ctx => ctx.Kernel.Get<Configuration>().BuildSessionFactory()).InSingletonScope(); 
    } 

    private ISession CreateSessionProxy(IContext ctx) 
    { 
     var session = (ISession)this.proxyGenerator.CreateInterfaceProxyWithoutTarget(typeof(ISession), new[] { typeof(ISessionImplementor) }, ctx.Kernel.Get<SessionInterceptor>()); 
     return session; 
    } 
} 

public class SessionInterceptor : IInterceptor 
{ 
    private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 

    private readonly Func<ISession> sessionProvider; 

    public SessionInterceptor(Func<ISession> sessionProvider) 
    { 
     this.sessionProvider = sessionProvider; 
    } 

    public void Intercept(IInvocation invocation) 
    { 
     try 
     { 
      var session = this.sessionProvider(); 
      invocation.ReturnValue = invocation.Method.Invoke(session, invocation.Arguments); 
     } 
     catch (TargetInvocationException exception) 
     { 
      Log.Error(exception); 
      throw; 
     } 
    } 
} 

這樣,您可以使用隨處可見的Isession無需關心細節。您可以使用InScope(ctx => OperationContext.Current)編輯InRequestScope以使用WCF範圍