Currently I cache the ServiceChannelFactory and create a new ServiceChannel every time I need one. I expected the ServiceChannels to be disposed by the garbage collector. However, the factory keeps a reference to each channel, so that it can close the channel when you call ServiceFactoryChannel.Close(). This results in many old channels being alive up to the point that everything stops working.
How can I cache the factory and still let the garbage collector dispose of my channels?
My code looks like this:
public class ServiceChannel
{
// Returns a ServiceChannel
public static TService Get<TService>()
{
var factory = GetChannelFactory<TService>();
string url = GetEndpoint<TService>();
var endPoint = new EndpointAddress(url);
return factory.CreateChannel(endPoint);
}
// Returns a ServiceChannelFactory, preferably from the cache
public static ChannelFactory<TService> GetChannelFactory<TService>()
{
var cacheKey = string.Format("MyProduct.Library.ServiceChannel.GetChannelFactory<{0}>()", typeof(TService));
var cache = HttpRuntime.Cache;
var factory = cache[cacheKey] as ChannelFactory<TService>;
if (factory == null)
{
factory = GetChannelFactoryUncached<TService>();
cache.Insert(cacheKey, factory);
}
return factory;
}
}
You could use an IoC container like Autofac/Unity/Ninject, or for a very basic but fast one use DynamoIOC.
When setting up your container, have a single reference to ServiceChannelFactory. When you create an IServiceChannel (to your service IMyService), register it as well.
But be careful, when your IServiceChannel.Faulted event is hit, you will need to close, dispose and recreate it, adding it back into the IoC container. This way, whenever a caller requires access to your service, it will be in a non-faulted state.
Related
I've googled a lot and none of the answers seem to be answering my question, hopefully it'll not be a duplicate.
I'm working on a service which I would not rather rebuild completely and keep it as it was and just implement my part of a deal into it.
There is a service which has an instance of a wcf gateway created by autofac, it is a SingleInstance() as such:
public static void RegisterMyService(ContainerBuilder builder)
{
builder.Register(c => new DesiredGatewayInterceptor());
builder
.Register(
c =>
{
const string BindingName = "BasicHttpBinding_My_PortType";
Uri endpointAddress = null;
ClientSection servicesSection = (ClientSection)WebConfigurationManager.GetSection("system.serviceModel/client");
foreach (ChannelEndpointElement endpoint in servicesSection.Endpoints)
{
if (endpoint.Name == BindingName)
{
endpointAddress = endpoint.Address;
break;
}
}
ChannelFactory<DesiredGateway> channel = new ChannelFactory<DesiredGateway>(
new BasicHttpBinding(BindingName),
new EndpointAddress(endpointAddress));
NameValueCollection section = (NameValueCollection)ConfigurationManager.GetSection("CredentialsConfiguration");
channel.Credentials.UserName.UserName = section["DesiredGatewayUser"];
channel.Credentials.UserName.Password = section["DesiredGatewayPassword"];
return channel;
})
.SingleInstance();
builder
.Register(c => c.Resolve<ChannelFactory<DesiredGateway>>().CreateChannel())
.InterceptTransparentProxy(typeof(DesiredGateway))
.InterceptedBy(typeof(DesiredGatewayInterceptor))
.UseWcfSafeRelease();
}
I've read about OperationContextScope() to manipulate headers but since this gateway instance is registered by autofac I am unable to cast appropriately to IContextChannel.
using (OperationContextScope scope = new OperationContextScope((IContextChannel)desiredGateway))
{
// Do some stuff with headers now
}
Such cast gives me an exception since instance of desiredGateway is wrapped in some kind of container, which is not IContextChannel, but once I create my own instance of a desiredGateway using channel.CreateChannel() I am able to cast to IContextChannel.
Target is to be able to inject a header value upon each call to desiredGateway, is there any way to achieve this without rebuilding existing implementation too much? Maybe there exists a cleaner way to achieve the above?
So I ended up removing those lines from gateway registration:
.InterceptTransparentProxy(typeof(DesiredGateway))
.InterceptedBy(typeof(DesiredGatewayInterceptor))
This allowed me to then cast to IContextChannel and I implemented interseption process within a class that owned an instance of the gateway using a generic method.
Consider the following C# code using MemoryCache to generate a new value for a given key if not already preset in the cache:
private static MemoryCache _memoryCache = new MemoryCache();
public T Apply<T>(string key, Func<T> factory)
{
var expiration ...
var newValue = new Lazy<T>(factory);
var value = (Lazy<T>)_memoryCache.AddOrGetExisting(key, newValue, expiration);
return (value ?? newValue).Value;
}
Consider now this:
var hugeObject = new HugeObject();
return cache.Apply("SomeKey", () =>
{
return hugeObject.GetValue();
});
The factory will be invoked "immediately" after AddOrGetExisting or never, so the question is:
Does the Lazy class clear the reference to the factory delegate after having generated the value (so all the resources used by the factory like, in this case, hugeObject, can be released)?
Looking at the reference source, I believe it does release the factory, and call out why:
// We successfully created and stored the value. At this point, the value factory delegate is
// no longer needed, and we don't want to hold onto its resources.
m_valueFactory = ALREADY_INVOKED_SENTINEL;
There is quite a lot of threading code in there so I'm not sure it does so every time, but you'd hope that if they've realise they need to, they will have done so properly.
I'm trying to persist an XPObject. Here's my code:
Administrateur adm = (Administrateur)GetUserByLogin("admin");
Client clt = (Client)GetUserByLogin("client");
using(var uow = new UnitOfWork())
{
Calendrier cal = new Calendrier(uow)
{
//Some string and int attributes
Administrateur = adm,
Client = clt
};
uow.CommitChanges();
}
GetUserByLogin is a method that returns an Utilisateur object, where Administrateur and Client inherit from Utilisateur.
I tested GetUserByLogin and it works fine. When I run the code above here's what I get:
S
ystem.ObjectDisposedException: Cannot access a disposed object.
Object name: 'ASTDataLayer.POCO.Administrateur(1004)'.
at DevExpress.Xpo.PersistentBase.get_Session()
at DevExpress.Xpo.Session.ThrowIfObjectFromDifferentSession(Object obj)
at DevExpress.Xpo.Metadata.XPMemberInfo.ProcessAssociationRefChange(Session s
ession, Object referenceMemberOwner, Object oldValue, Object newValue, Boolean s
kipNonLoadedCollections)
Please help, Thanks
using (UnitOfWork uow = new UnitOfWork() {
// Do something
}
using (UnitOfWork uow = new UnitOfWork() {
// Do something
return persistentObjectOrCollectionOfPersistentObjects;
}
There is a big confusion about when and how to dispose of the Session
or UnitOfWork. The code snippets above illustrate the correct and the
incorrect approach.
If you created a UnitOfWork or Session instance just to perform some
actions in the current context, you can safely dispose of the
UnitOfWork or Session instance. But if you pass persistent objects to
another function, you should not immediately dispose of the Session or
UnitOfWork.
In the latter case, the task to dispose of the UnitOfWork/Session
instance becomes tricky. You have to make sure that none of your code
will use persistent objects loaded by the Session/UnitOfWork after you
dispose it.
The code you posted does not contain error that can lead to the exception you received. I suppose that this error exists in the GetUserByLogin method. Otherwise, it is difficult to imagine where else you might dispose the Session instance that is used in your code later.
The GetUserByLogin method is most probably creates a new Session instance. Obviously, this is necessary and cannot be avoided. But this method cannot dispose of the Session, because it return a persistent object as result. This object will be used later and the Session can be accessed for certain purposes. It is correctly to dispose the Session in the code that consumes the GetUserByLogin method.
However, there is another problem. Since your application logic requires to call the GetUserByLogin method multiple times in the same context, you will be mixing different Sessions if you will try to use returned objects together. For example, assign them to reference properties of a third object. This is what you did, by the way.
So, my suggestion is to modify the GetUserByLogin method, so it accepts the Session as parameter. In this situation, you will always be sure that you are using a single Session instance, and can dispose it before exiting the context.
using(var uow = new UnitOfWork())
{
Administrateur adm = (Administrateur)GetUserByLogin(uow, "admin");
Client clt = (Client)GetUserByLogin(uow, "client");
Calendrier cal = new Calendrier(uow)
{
//Some string and int attributes
Administrateur = adm,
Client = clt
};
uow.CommitChanges();
}
DBContexts are short lived, created and destroyed with every request. I have a number of tasks that I'd like to perform prior to and post save and I'd like to handle these with some sort of eventing model. I'm wondering in RX is the right route.
Is there some way of creating a singleton "hub" then causing my DBContext to raise BeforeChange (SavingChanges event) and post save (no applicable event) Observables and "push" them into the long lived hub.
In effect I'd like to do this in my "hub" singleton
public IObservable<EventPattern<EventArgs>> Saves = new Subject<EventPattern<EventArgs>>();
public void AttachContext(DbContext context)
{
Saves = Observable.FromEventPattern<EventArgs>(((IObjectContextAdapter)context).ObjectContext, "SavingChanges");
}
but in such a way that AttachContext simply feed its generated observable into the exisitng Saves observabe, rather than replacing it (and all of its subscriptions)?
Yes. Use a nested observable + merge:
private readonly Subject<IObservable<EventPattern<EventArgs>> _contexts = new Subject<IObservable<EventPattern<EventArgs>>();
private readonly IObservable<EventPattern<EventArgs>> _saves = _contexts.Merge();
public IObservable<EventPattern<EventArgs>> Saves { get { return _saves; } }
public void AttachContext(DbContext context)
{
_contexts.OnNext(Observable.FromEventPattern<EventArgs>(((IObjectContextAdapter)context).ObjectContext, "SavingChanges"));
}
The only problem with this is that the list of contexts being observed will grow unbounded since the Observable.FromEventPattern never completes. So this is effectively a memory leak as coded.
If you know that the db context will be used for a single save, then you could add a .FirstAsync() to the end of the call to Observable.FromEventPattern. This will cause your subject to stop watching the context once it has seen an event from it.
This still suffers from the problem that maybe a context is attached but its Save is never performed (due to logic, or an error or whatever).
The only way I know to resolve the problem is to change AttachContext to return an IDisposable that the caller must use when they want to detach the context:
public IDisposable AttachContext(DbContext context)
{
var detachSignal = new AsyncSubject<Unit>();
var disposable = Disposable.Create(() =>
{
detachSignal.OnNext(Unit.Default);
detachSignal.OnCompleted();
});
var events = Observable.FromEventPattern<EventArgs>(((IObjectContextAdapter)context).ObjectContext, "SavingChanges");
_contexts.OnNext(events.TakeUntil(detachSignal));
return disposable;
}
This is the point, I have a WCF service, it is working now. So I begin to work on the client side. And when the application was running, then an exception showed up: timeout. So I began to read, there are many examples about how to keep the connection alive, but, also I found that the best way, is create channel, use it, and dispose it. And honestly, I liked that. So, now reading about the best way to close the channel, there are two links that could be useful to anybody who needs them:
1. Clean up clients, the right way
2. Using Func
In the first link, this is the example:
IIdentityService _identitySvc;
...
if (_identitySvc != null)
{
((IClientChannel)_identitySvc).Close();
((IDisposable)_identitySvc).Dispose();
_identitySvc = null;
}
So, if the channel is not null, then is closed, disposed, and assign null. But I have a little question. In this example the channel has a .Close() method, but, in my case, intellisense is not showing a Close() method. It only exists in the factory object. So I believe I have to write it. But, in the interface that has the contracts or the class that implemets it??. And, what should be doing this method??.
Now, the next link, this has something I haven't try before. Func<T>. And after reading the goal, it's quite interesting. It creates a funcion that with lambdas creates the channel, uses it, closes it, and dipose it. This example implements that function like a Using() statement. It's really good, and a excellent improvement. But, I need a little help, to be honest, I can't understand the function, so, a little explanatino from an expert will be very useful. This is the function:
TReturn UseService<TChannel, TReturn>(Func<TChannel, TReturn> code)
{
var chanFactory = GetCachedFactory<TChannel>();
TChannel channel = chanFactory.CreateChannel();
bool error = true;
try {
TReturn result = code(channel);
((IClientChannel)channel).Close();
error = false;
return result;
}
finally {
if (error) {
((IClientChannel)channel).Abort();
}
}
}
And this is how is being used:
int a = 1;
int b = 2;
int sum = UseService((ICalculator calc) => calc.Add(a, b));
Console.WriteLine(sum);
Yep, I think is really, really good, I'd like to understand it to use it in the project I have.
And, like always, I hope this could be helpful to a lot of people.
the UseService method accepts a delegate, which uses the channel to send request. The delegate has a parameter and a return value. You can put the call to WCF service in the delegate.
And in the UseService, it creates the channel and pass the channel to the delegate, which should be provided by you. After finishing the call, it closes the channel.
The proxy object implements more than just your contract - it also implements IClientChannel which allows control of the proxy lifetime
The code in the first example is not reliable - it will leak if the channel is already busted (e.g. the service has gone down in a session based interaction). As you can see in the second version, in the case of an error it calls Abort on the proxy which still cleans up the client side
You can also do this with an extension method as follows:
enum OnError
{
Throw,
DontThrow
}
static class ProxyExtensions
{
public static void CleanUp(this IClientChannel proxy, OnError errorBehavior)
{
try
{
proxy.Close();
}
catch
{
proxy.Abort();
if (errorBehavior == OnError.Throw)
{
throw;
}
}
}
}
However, the usage of this is a little cumbersome
((IClientChannel)proxy).CleanUp(OnError.DontThrow);
But you can make this more elegant if you make your own proxy interface that extends both your contract and IClientChannel
interface IPingProxy : IPing, IClientChannel
{
}
To answer the question left in the comment in Jason's answer, a simple example of GetCachedFactory may look like the below. The example looks up the endpoint to create by finding the endpoint in the config file with the "Contract" attribute equal to the ConfigurationName of the service the factory is to create.
ChannelFactory<T> GetCachedFactory<T>()
{
var endPointName = EndPointNameLookUp<T>();
return new ChannelFactory<T>(endPointName);
}
// Determines the name of the endpoint the factory will create by finding the endpoint in the config file which is the same as the type of the service the factory is to create
string EndPointNameLookUp<T>()
{
var contractName = LookUpContractName<T>();
foreach (ChannelEndpointElement serviceElement in ConfigFileEndPoints)
{
if (serviceElement.Contract == contractName) return serviceElement.Name;
}
return string.Empty;
}
// Retrieves the list of endpoints in the config file
ChannelEndpointElementCollection ConfigFileEndPoints
{
get
{
return ServiceModelSectionGroup.GetSectionGroup(
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None)).Client.Endpoints;
}
}
// Retrieves the ConfigurationName of the service being created by the factory
string LookUpContractName<T>()
{
var attributeNamedArguments = typeof (T).GetCustomAttributesData()
.Select(x => x.NamedArguments.SingleOrDefault(ConfigurationNameQuery));
var contractName = attributeNamedArguments.Single(ConfigurationNameQuery).TypedValue.Value.ToString();
return contractName;
}
Func<CustomAttributeNamedArgument, bool> ConfigurationNameQuery
{
get { return x => x.MemberInfo != null && x.MemberInfo.Name == "ConfigurationName"; }
}
A better solution though is to let an IoC container manage the creation of the client for you. For example, using autofac it would like the following. First you need to register the service like so:
var builder = new ContainerBuilder();
builder.Register(c => new ChannelFactory<ICalculator>("WSHttpBinding_ICalculator"))
.SingleInstance();
builder.Register(c => c.Resolve<ChannelFactory<ICalculator>>().CreateChannel())
.UseWcfSafeRelease();
container = builder.Build();
Where "WSHttpBinding_ICalculator" is the name of the endpoint in the config file. Then later you can use the service like so:
using (var lifetime = container.BeginLifetimeScope())
{
var calc = lifetime.Resolve<IContentService>();
var sum = calc.Add(a, b);
Console.WriteLine(sum);
}