2017-02-02 7 views
0

Я инъекционного бизнес-слой в самопринятый (InstanceContextMode = за вызов) службы WCF за счет использования ServiceHost.AddDependencyInjectionBehavior() расширение AutoFac (как описано в Autofac documentation)Autofac с самодостаточно службы WCF и удаления объекта

В моем бизнес-слое используются компоненты, которые нельзя воссоздавать каждый раз, когда приходит новый запрос (предположим, что для этого требуется постоянное соединение с базой данных).

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

builder.RegisterType<BusinessLayer>() 
    .SingleInstance(); 

Инъекция бизнес-слой в службу WCF работает нормально; моя проблема в том, что:

Dispose() не вызван ни в какие сервисы, созданные в контейнере: не только сам бизнес-уровень, но и «постоянные» службы.

Я ожидаю, что это произойдет для службы BL. Из Autofac docs снова:

Если у вас есть одноэлементные компоненты (зарегистрированные в качестве SingleInstance()) они будут жить жизнь контейнера. Поскольку время жизни контейнера обычно является временем жизни приложения, это означает, что компонент не будет размещен до конца приложения.

, но почему их нет моего «ребенка» (Autofac зарегистрированных) услуг (то есть «» IPersistentService ниже), расположенный, когда область Время жизни - при условии, что я явно не делает их «SingleInstance «? Примечание:: это еще случай, если я вручную выбрасывайте обслуживание бизнес-слоя в пределах срока службы объема после того, как закрыть ServiceHost

Э.Г. (IDisposable реализаций для краткости опускаем):

[ServiceContract] 
public interface IMyService 
{ 
    void DoStuff(); 
} 
public class MyService : IMyService 
{ 
    IBusinessLayer _bl; 
    public MyService(IBusinessLayer bl) 
    { 
     _bl = bl; 
    } 

    public void DoStuff() 
    { 
     _bl.BLDoStuff(); 
    } 
} 

public interface IBusinessLayer 
{ 
    void BLDoStuff(); 
} 
public class BusinessLayer : IBusinessLayer 
{ 
    IPersistentService _service; 
    public BusinessLayer(IPersistentService service) 
    { 
     _service = service; 
    } 
    public void BLDoStuff() 
    { 
     // Do something that requires a 'cached'/persistent component 
     _service.DoSomethingWithPersistentConnection(); 
    } 
} 

public interface IPersistentService : IDisposable 
{ 
    void DoSomethingWithPersistentConnection(); 
} 

С регистрацией Autofac ищут что-то вроде:

builder.RegisterType<BusinessLayer>() 
    .SingleInstance(); 

builder.RegisterType<MyPersistentService>() 
    .As<IPersistentService>() 
    .OnActivated(e => e.Instance.Start()); 
+0

«Почему ни одна из моих« дочерних »(зарегистрированных через Autofac) служб (т. Е.« IPersistentService »ниже), если область действия« равна ». Эту проблему обычно называют [Captive Dependency] (http://blog.ploeh.dk/2014/06/02/captive-dependency/). – Steven

+0

Справа. Ип, это объясняет - и спасибо за ссылку на это описание. – Ive

ответ

1

Как упоминалось Стивен, что вы испытываете здесь пленником проблема иждивенчества. Другими словами, singleton (BusinessLayer, зарегистрированный .SingleInstance()) сохраняет зависимость от продолжительности жизни или переходный период (MyPersistentService, зарегистрированный по умолчанию как переходный).

Положите это так, зависимости однопользовательских сервисов всегда будут одиночными, независимо от того, как они были зарегистрированы в контейнере. Диаграмма в Mark Seeman's article, с которой связан Стивен, дает хорошее представление об этом.

Я думаю, что вы можете достичь того, чего ожидаете, но ваши регистрации ошибочны.

В моем бизнес-слое используются компоненты, которые нельзя воссоздавать каждый раз, когда приходит новый запрос (допустим, для него требуется постоянное соединение с базой данных).

Таким образом, при создании контейнера, я хотел бы, чтобы зарегистрировать услугу BL в качестве единого экземпляра

Это где проблема. Это зависимость бизнес-сервиса, который должен быть зарегистрирован как однотонный, а не сам бизнес-сервис. Это означает, что у вас может быть Autofac создать другой экземпляр BusinessLayer для каждого вызова WCF, но введенный экземпляр MyPersistentService всегда будет таким же. Имеет ли это смысл? Ваши регистрации будет выглядеть:

builder 
    .RegisterType<BusinessLayer>() 
    .As<IBusinessLayer>() 
    .InstancePerLifetimeScope(); // a new instance per WCF call 

builder 
    .RegisterType<MyPersistentService>() 
    .As<IPersistentService>() 
    .OnActivated(e => e.Instance.Start()) 
    .SingleInstance(); // one same instance for the lifetime of the application 

Один экземпляр MyPersistenService затем будет удаляться только после утилизации корневой контейнер (который вы создали, позвонив builder.Build()) после закрытия узла службы.

+0

Спасибо за объяснение - да, как уже упоминал @Steven, так называемая «зависимость от людей» - это моя проблема. Однако я действительно хотел бы использовать удаление объекта Autofac для очистки «постоянных» сервисов. Не похоже, что это будет возможно, хотя, если я определяю их как синглтоны, поэтому я пытаюсь обойти это, сделав вместо этого BL-сервис одним синглом. – Ive

+0

Я не понимаю. Если постоянный сервис нельзя воссоздавать для каждого запроса, почему он должен быть удален после каждого запроса? Это звучит противоречиво для меня. –

+0

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