Реализация сеанса за запрос для WCF, NHibernate и Ninject

Я пытаюсь реализовать модель сеанса за запрос в моем приложении WCF, и я прочитал бесчисленные документы по этой теме, но похоже, что это не полная демонстрация этого. Я натолкнулся на некоторые очень полезные статьи, такие как этот:

NHibernate ISession, ограниченный одним WCF-вызовом

но все они из старых дней, когда NHibernate и Ninject не имели конкретных реализаций WCF, поэтому они достигли того, что мне нужно, внедряя своих заказных поставщиков услуг и т.д. Так как у Ninject и NHibernate есть поддержка WCF сейчас, я хочу держите вещи в согласии, используя их модули, но я оказался здесь...

Базовая установка и поток должны быть примерно такими:

  • Установить CurrentSessionContext в WcfOperationSessionContext в конфигурации nhibernate
  • При запуске службы, начале запроса или в любом месте вокруг времени инициализации откройте сеанс и привяжите его к текущему контексту.
  • Репозитории получают текущий экземпляр сеанса, используя метод SessionFactory.GetCurrentSession()
  • Отменить и закрыть сеанс в конце жизненного цикла

Моя первоначальная проблема заключалась в том, что я не смог получить доступ к жизненному циклу wcf для обработки привязок. После некоторого копания в код ninject мне удалось подключить мои методы к событиям открытия/закрытия ServiceHost без значительных изменений, но тогда я не смог получить доступ к OperationContext, поскольку он является поточно-статическим.

Позже я попытался включить совместимость asp.net и использовать Application_BeginRequest и Application_EndRequest, и это выглядело очень многообещающим, но я не думаю, что лучшее решение, поскольку я должен привязывать материал к экземпляру службы, а не HTTP-запрос.

Кто-нибудь когда-либо достигал этого, используя встроенные библиотеки расширения wcf ninject? Или любые идеи о том, что я могу делать неправильно?

Ответ 1

Я выполнил за всю жизнь сеанса запроса с помощью IDispatchMessageInspector. Вероятно, вы могли бы реализовать пользовательский менеджер времени жизни для Ninject для достижения каждого веб-запроса.

Ответ 2

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, не заботясь о деталях. Вы можете редактировать InRequestScope с помощью InScope (ctx = > OperationContext.Current) для использования области WCF

Ответ 3

Возможно, вы сможете это сделать, используя точки расширения, указанные в интерфейсе IInstanceContextProvider.