0

since I couldn't find the appropriate answer to my question in a couple hours, I'm posting it here.

I have a WPF/WCF application with shared interface (IService) library and dynamically created proxies (created with CreateChannel). The main problem is that proxies are not being closed/disposed and I'm getting this exception at 200-th service call:

The system hit the limit set for throttle 'MaxConcurrentSessions'. Limit for this throttle was set to 200. Throttle value can be changed by modifying attribute 'maxConcurrentSessions' in serviceThrottle element or by modifying 'MaxConcurrentSessions' property on behavior ServiceThrottlingBehavior.

Interestingly, the same proxy works fine with BasicHttpBinding!

It seems that NetNamedPipeBinding proxies are not being closed and disposed automatically. Here are some client side code snippets.

// creation of ChannelFactory - only one for each service interface
public static ChannelFactory<T> CreateChannelFactory(string serviceAddress)
{
    Binding binding = new NetNamedPipeBinding()
    {
        // setting quotas and timeouts                
    };            

    ChannelFactory<T> factory = new ChannelFactory<T>(binding, new EndpointAddress(serviceAddress));

    factory.Endpoint.Behaviors.Add(new AuthenticationBehavior()); // custom IEndpointBehavior

    foreach (OperationDescription op in factory.Endpoint.Contract.Operations)
    {
        DataContractSerializerOperationBehavior dataContractBehavior = op.Behaviors.Find<DataContractSerializerOperationBehavior>() as DataContractSerializerOperationBehavior;
        if (dataContractBehavior != null)
        {
            dataContractBehavior.MaxItemsInObjectGraph = 2147483647;
        }
    }                                     

    return factory;
}

public static T GetService()
{
    // simplified - actually holding a collection of CFs and creating each factory only once
    return ChannelFactoryHelper<T>.CreateChannelFactory(serviceAddress).CreateChannel();
}

// creation of the proxy - new for each WCF call
IService svc = ServiceHelper<IService>.GetService();    
... // calling the service

You can see I'm not using the "using" statement, since the proxy doesn't implement IDisposable. First question is, how would I do that. On the client side, I'm using the IService as a proxy type. If I wanted the IService to be IDisposable, I'd have to implement the dispose method on the service side - since my Service implements IService. That doesn't seem logical - to call service method to dispose that service...

Since It'd be better not to change all code for service calls to "using": is there any way to auto dispose the proxy when not in use anymore? Why is that not done automatically? Please note that I'm using custom IExtensionBehavior - could that be the reason?

Any help would be appreciated. Thank you!

dabor
  • 127
  • 1
  • 3
  • 13
  • You can try this first when your processing is done: System.GC.Collect() After that, I think you're stuck implementing iDisposable – Brian Jun 13 '13 at 13:31
  • Tried that already, thanks... Doesn't work, though. The only way for implementing IDisposable, as I see it, is creating a wrapper class for each service and repeating all of its methods. Any "partial" implementation possible (to just add IDisposable implementation on the client)? – dabor Jun 14 '13 at 04:59
  • dabor It was worth a try ... – Brian Jun 14 '13 at 08:08

1 Answers1

0

Firstly, you will find that the service proxy object returned from the CreateChannel method does implement IDisposable, because IClientChannel derives from IDisposable. However, you should not use a standard using block to leverage this because hard-to-diagnose exceptions can occur at the closing bracket if the channel has faulted while you were using it.

Maybe you might find some variant of the following pattern an improvement compared to laboriously implementing IDisposable explicitly in a wrapper for every service proxy type. You can implement the pattern in a generic function accepting a delegate (Action<IService>) to do the "calling the service" bit.

IService svc;
try
{
    // creation of the proxy - new for each WCF call
    svc = ServiceHelper<IService>.GetService();    
... // calling the service
    myDelegateDoingStuffWithService(svc);
}
finally
{
    try
    {
        ((ICommunicationObject)svc).Close();
    }
    catch (CommunicationException ex)
    {
        ((ICommunicationObject)svc).Abort();
    }
}
Chris Dickson
  • 11,964
  • 1
  • 39
  • 60