Как воссоздать Службу WCF как экземпляр Singleton с SimpleInjector (используя Tridion)
Я использую контейнер IoC SimpleInjector. Я знаю, что синглтоны не должны быть воссозданы, так как это не является их целью, но моя проблема с WCF, и когда он переходит в состояние Faults, которое, согласно нескольким прочтениям, не может быть восстановлено, и необходимо создать новый экземпляр.
У меня есть класс с именем CoreServiceService, который использует две службы WCF.
- CoreService
- 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
}
}
}
}