Reputation: 4319
I'm using the IoC Container SimpleInjector
.
I know that Singletons shouldn't be recreated since that's not their purpose but my problem is with WCF and when it enters into Faulted state which according to several readings it cannot be recovered and a new instance needs to be created.
I have a class named CoreServiceService
which uses two WCF Services.
CoreService
ECLService
I want those services to be singleton since I'll be making lots of calls to CoreServiceSession
and creating those WCF Service is too expensive and takes a lot of times, after the creation, they are much faster.
I'm registering them like this:
container.Register(() => new SessionAwareEclServiceClient(binding, eclServiceRemoteAddress), Lifestyle.Singleton);
container.Register(() => new SessionAwareCoreServiceClient(binding, coreServiceRemoteAddress), Lifestyle.Singleton);
container.Register(typeof(ICoreServiceSession), typeof(CoreServiceSession), Lifestyle.Scoped);
My problem is that while using ECLService
if something cannot be retrieved is enters into Faulted connection, In that case, I call .Abort()
and close the connection. But the next time I call my service ECLService
WCF service keeps being in the Faulted
state (since it's a singleton) so I need a way to recreate the connection.
I tried with something like:
coreServiceSession.EclServiceClient = (SessionAwareEclServiceClient)container.GetInstance(typeof(SessionAwareEclServiceClient));
But, of course, it gives me the same instance.
I also tried using this initializer:
container.RegisterInitializer<ICoreServiceSession>(coreServiceSession =>
{
if (coreServiceSession.EclServiceClient.State == CommunicationState.Faulted)
{
coreServiceSession.EclServiceClient.Abort();
coreServiceSession.EclServiceClient = null;
coreServiceSession.EclServiceClient = (SessionAwareEclServiceClient)container.GetInstance(typeof(SessionAwareEclServiceClient));
}
}
Same thing and I tried to use instead of container.GetInstance, this:
coreServiceSession.EclServiceClient = new SessionAwareEclServiceClient(binding, eclServiceRemoteAddress);
Same things. Any ideas/options?
It there any way to force to get a new instance in this case?
UPDATE
This is part of the class 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();
}
}
Thanks in advance. Guillermo
Upvotes: 2
Views: 784
Reputation: 172606
@ScottHannen already gave the answer in his comment: do not register channels as singletons: they are not expensive to create, only the channel factories are.
As a matter of fact, you shouldn't inject your WCF client objects into constructors at all. Injecting them into a constructor implies that they are a useful abstraction that can be used to intercept, mock or replace, while the class using such client is typically strongly coupled to WCF.
So instead of injecting them into a constructor, let the consumer create them internally using the ChannelFactory
. Even such ChannelFactory
typically doesn't have to be injected, you can just new it up in a private static field.
This is how your CoreServiceSession
might look like:
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
}
}
}
}
Upvotes: 1