Good Afternoon.
I'm facing a problem with memory leak, and I think I know the point where this occurs, but don't know what I need to do to fix it ! Hope you guys can save me again.
I truly have tried to google it (a lot), but none of the results I found or tests I made actually worked.
I'm using a big mix of features, but I had to follow some architecture rules from my client's IT department, so this topic can't be considered, like don't use Ninject or don't use WCF for example. What I can do (and probably I will need to) is change the way they are implemented.
That said, let's go to the bomb.
On my project, the presentation layer is hosted in one server, the WCF Services and all his dependencies (Domain, Repository, etc) are in another one.
The problem is in the WCF server, this server increase memory usage on every request from the presentation to service, and doesn't release this memory until the server memory reach the limit, and the server need to be rebooted, or the IIS Application Pool be restarted.
Below the used technologies:
Domain model, WCF, MVC4 with Web API, Ninject 3.2 in MVC and WCF, AutoMapper for mapping from domain to dto and reverse, Repository and NHibernate.
I've already checked the Repository and the NHibernate layers, and they are correctly disposing their objects.
I'm using Ninject to inject WCF in presentation as follow in App_Start:
public class NinjectConfiguration
{
public void Configure(IKernel container)
{
AddBindings(container);
var resolver = new NinjectDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
private void AddBindings(IKernel container)
{
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>());
// ...
}
public TService CreateChannel<TService>() where TService : class
{
var factory = new ChannelFactory<TService>(string.Empty);
factory.Open();
return factory.CreateChannel();
}
}
The presentation Web.Config endpoint configuration:
<system.serviceModel>
<client>
<endpoint address="http://MyEndPoint/PersonService.svc" binding="wsHttpBinding" bindingConfiguration="BindClientConfig" contract="MyContract.IPersonService" />
</client>
<bindings>
<wsHttpBinding>
<binding name="BindClientConfig" maxReceivedMessageSize="2147483647" sendTimeout="00:01:00"></binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
My WEBApi Dispose:
public class PersonController : ApiController
{
IPesrsonService _personService;
public PersonController(IPesrsonService personParam) { ... }
//Gets, Post, Put, Delete here and functional
protected override void Dispose(bool disposing)
{
if (_personService != null)
{
_personService.Dispose(); //This point is reached
}
base.Dispose(disposing);
}
}
And my WCF Dispose (The contract implements IDisposable):
public class PersonService : IPersonService
{
private IPersonDomain _personDomain;
public PersonService(IPersonDomain personDomainParam) { ... }
//...
protected virtual void Dispose(bool disposing) { ... }
public void Dispose()
{
Dispose(true); //This point is NEVER reached
GC.SuppressFinalize(this);
}
}
In theory, the _personService.Dispose from WebAPI must call the Dispose from WCF, but this Dispose WCF is never reached. I can reach any other methods from the WCF, but the Dispose, I can't.
My guess is that I'm missing something on the Ninject configuration, that creates this unmanaged hole.
It seems that the presentation layer do not actually close the connection to WCF, that way, leaving the endpoint open forever in the other side of the communication (WCF Server) and keeping the allocated memory there.
I've already tried to change the NinjectConfiguration as below, but without success:
private void AddBindings(IKernel container)
{
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>());
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).InScope(ctx => HttpContext.Current);
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).OnDeactivation(CloseServiceConnection);
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).OnDeactivation(CloseServiceConnection<IPersonService>);
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).InScope(ctx => HttpContext.Current).OnDeactivation(CloseServiceConnection);
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).InScope(ctx => HttpContext.Current).OnDeactivation(CloseServiceConnection<IPersonService>);
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).InScope(ctx => OperationContext.Current).OnDeactivation(CloseServiceConnection<IPersonService>);
}
public static void CloseServiceConnection<T>(T service)
{
(service as IDisposable).Dispose();
}
Maybe the CreateChannel from NinjectConfiguration class can be created in another way so I can call channel.Close(), but I don't know how to do it.
But all this is just a guess. Everything you post I'll try.
I appreciate any help, and thank you so much for your time.
Elek Guidolin