WCF,NHibernate和Ninject的每个请求的会话实现

时间:2011-02-01 20:10:03

标签: wcf nhibernate ninject session-per-request

我正在尝试在我的WCF应用程序中实现每请求会话模型,并且我已经阅读了关于此主题的无数文档,但看起来没有完整的演示。我实际上遇到过一些非常有用的文章,例如:

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

但这些都来自NHibernate和Ninject没有WCF特定实现的旧时代,因此他们通过实现他们的自定义服务提供程序等来实现我所需要的。因为Ninject和NHibernate现在都支持WCF,我想通过使用他们的模块保持一致,但我最终在这里......

基本设置和流程应该是这样的:

  1. 在nhibernate配置中将CurrentSessionContext设置为WcfOperationSessionContext
  2. 在服务启动,开始请求或初始化时间的任何地方,打开会话并将其绑定到当前上下文
  3. 存储库使用SessionFactory.GetCurrentSession()方法获取当前会话实例
  4. 在生命周期结束时取消绑定并关闭会话
  5. 我最初的问题是我无法访问wcf生命周期来处理我的绑定。在深入研究ninject代码后,我设法将我的方法挂钩到ServiceHost的Opening / Closing事件而没有太大变化,但后来我无法访问OperationContext,因为它是线程静态的。

    后来我尝试启用asp.net兼容性并使用Application_BeginRequest和Application_EndRequest,它看起来非常有前景,但我不认为这是最好的解决方案,因为我应该将东西绑定到服务实例,而不是http请求。

    有没有人使用ninject的内置wcf扩展库实现了这一目标?或者对我可能做错的任何想法?

3 个答案:

答案 0 :(得分:2)

我已在IDispatchMessageInspector的帮助下实现了每个请求的会话生命周期。 可能您可以为Ninject实现自定义生命周期管理器以实现每个Web请求。

答案 1 :(得分:1)

HY

您可以执行以下操作:

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 =&gt; OperationContext.Current)编辑InRequestScope以使用WCF范围

答案 2 :(得分:0)

您可以使用IInstanceContextProvider界面中提供的扩展点来完成此操作。