开发者

session-per-request implementation for WCF, NHibernate, and Ninject

开发者 https://www.devze.com 2023-02-08 12:07 出处:网络
I am trying to implement a session-per-request model in my WCF application, and I have read countless documents on this topic, but looks like there is not a complete demonstration of this. I actually

I am trying to implement a session-per-request model in my WCF application, and I have read countless documents on this topic, but looks like there is not a complete demonstration of this. I actually came across some very useful articles such as this one:

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

but these are all from the old days when NHibernate and Ninject did not have WCF specific implementations, therefore they achieved what I need by implementing their custom service providers, etc. Since both Ninject and NHibernate have WCF sup开发者_如何学编程port now, I want to keep things consistent by using their modules, but I ended up here...

The basic setup and flow should be something like this:

  1. Set CurrentSessionContext to WcfOperationSessionContext in nhibernate configuration
  2. On service start, begin request, or anywhere around the init time, open session and bind it to the current context
  3. Repositories get the current session instance using SessionFactory.GetCurrentSession() method
  4. Unbind and close session at the end of the lifecycle

My initial problem was that I wasn't able to access to the wcf lifecycle to handle my bindings. After digging into the ninject code a bit, I managed to hook my methods to ServiceHost's Opening / Closing events without changing much, but then I wasn't able to access to the OperationContext since it is thread-static.

Later I tried enabling asp.net compatibility and using Application_BeginRequest and Application_EndRequest, and it looked very promising, but I don't think that's the best solution since I should be binding stuff to the service instance, rather than the http request.

Has anyone ever achieved this using ninject's built-in wcf extension libraries? Or any ideas on what I might be doing wrong?


I have implemented per request session lifetime with the help of IDispatchMessageInspector. Probably you could implement custom lifetime manager for Ninject to achieve per web request.


Hy

You can do the following:

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

With that you can use everywhere ISession without caring about the details. You can edit InRequestScope with InScope(ctx => OperationContext.Current) to use WCF scope


You may be able to do it by using the extension points provided in the IInstanceContextProvider Interface.

0

精彩评论

暂无评论...
验证码 换一张
取 消