Как воссоздать Службу WCF как экземпляр Singleton с SimpleInjector (используя Tridion)

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

У меня есть класс с именем CoreServiceService, который использует две службы WCF.

  1. CoreService
  2. ECLService

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

Я регистрирую их как это:

container.Register(() => new SessionAwareEclServiceClient(binding, eclServiceRemoteAddress), Lifestyle.Singleton);

container.Register(() => new SessionAwareCoreServiceClient(binding, coreServiceRemoteAddress), Lifestyle.Singleton);

container.Register(typeof(ICoreServiceSession), typeof(CoreServiceSession), Lifestyle.Scoped);

Моя проблема заключается в том, что при использовании ECLService, если что-то не может быть получено, входит в Failed- соединение, в этом случае я вызываю.Abort() и закрываю соединение. Но в следующий раз, когда я позвоню своей службе, служба WCLS ECLService будет продолжать находиться в состоянии Faulted (так как это одноэлементная версия), поэтому мне нужен способ восстановить соединение.

Я пытался с чем-то вроде

coreServiceSession.EclServiceClient = (SessionAwareEclServiceClient)container.GetInstance(typeof(SessionAwareEclServiceClient));

Но, конечно, это дает мне тот же пример.

Я также пытался использовать этот инициализатор

container.RegisterInitializer<ICoreServiceSession>(coreServiceSession =>
{
    if (coreServiceSession.EclServiceClient.State == CommunicationState.Faulted)
    {
        coreServiceSession.EclServiceClient.Abort();
        coreServiceSession.EclServiceClient = null;
        coreServiceSession.EclServiceClient = (SessionAwareEclServiceClient)container.GetInstance(typeof(SessionAwareEclServiceClient));
    }
}

То же самое, и я попытался использовать вместо контейнера.GetInstance, это:

coreServiceSession.EclServiceClient = new SessionAwareEclServiceClient(binding, eclServiceRemoteAddress);

Тоже самое. Есть идеи / варианты?

Его там в любом случае заставить получить новый экземпляр в этом случае?

ОБНОВИТЬ

Это часть класса CoreServiceSession

public class CoreServiceSession : ICoreServiceSession
{
      public CoreServiceSession(ISessionAwareCoreService sessionAwareEclServiceClient, SessionAwareCoreServiceClient sessionAwareCoreServiceClient)
        {
            EclServiceClient = sessionAwareEclServiceClient;
            CoreServiceClient = sessionAwareCoreServiceClient;
        }

        public ISessionAwareCoreService EclServiceClient { get; set; }

        public SessionAwareCoreServiceClient CoreServiceClient { get; set; }

        public string CreateOrGetStubUris(string eclItemUri)
        {
            var stubInfo = EclServiceClient.CreateOrGetStubUris(new List<string> { eclItemUri }).FirstOrDefault();
        }
}

Заранее спасибо. Гильермо

1 ответ

@ScottHannen уже дал ответ в своем комментарии: не регистрируйте каналы как синглтоны: их создание не дорого, только фабрики каналов.

На самом деле, вы вообще не должны вставлять ваши объекты клиента WCF в конструкторы. Внедрение их в конструктор подразумевает, что они являются полезной абстракцией, которую можно использовать для перехвата, насмешки или замены, в то время как класс, использующий такой клиент, обычно тесно связан с WCF.

Поэтому вместо того, чтобы вводить их в конструктор, пусть потребитель создает их внутренне, используя ChannelFactory, Даже такой ChannelFactory обычно вводить не нужно, вы можете просто добавить его в приватное статическое поле.

Вот как твоя CoreServiceSession может выглядеть так:

public class CoreServiceSession : ICoreServiceSession
{
    private static readonly ChannelFactory factory =
        new ChannelFactory<ISessionAwareCoreService>(myBinding, myEndpoint);

    public string CreateOrGetStubUris(string eclItemUri)
    {
        var client = factory.CreateChannel();

        try
        {
            return EclServiceClient.CreateOrGetStubUris(
                new List<string> { eclItemUri }).FirstOrDefault();
        }
        finally
        {
            try
            {
                ((IDisposable)client).Dispose();
            }
            catch
            {
                // We need to swallow exceptions thrown by Dispose. 
                // See: https://marcgravell.blogspot.com/2008/11/dontdontuse-using.html
            }
        }
    }
}
Другие вопросы по тегам