none
ClientBase caching with ChannelFactory RRS feed

  • Question

  • Public Shared Function GetWCFObject(Of T)() As T
            Dim arrDetails As ArrayList = _endPointDefinition(GetType(T).ToString)
            If arrDetails Is Nothing Then
                Throw New RemotingException("A configured type could not be found. Please check spelling")
            End If
    
            Dim endPointConfigName As String = arrDetails.Item(0)
            Dim fact As New ChannelFactory(Of T)(endPointConfigName, New EndpointAddress(CType(System.Configuration.ConfigurationSettings.AppSettings("RemotingURI") & arrDetails.Item(1), String)))
            arrDetails = Nothing
            fact.Open()
    
            Return fact.CreateChannel()
        End Function
    I am using above code to create channel, I need to cache the channel. Is there any built in way or I need to write custom code. I can't use the proxy generation methods as there are many services and we are migrating from remoting to WCF. ClientBase.CacheSetting work with proxy generation only? I am using .NetFramework 4.5 and VS 2013.
    Wednesday, October 22, 2014 10:01 AM

Answers

  • Yes:

      public static class Proxy
        {
            public static T GetChannel<T>()
            {
                return ProxyManager<T>.GetProxy();
            }
        }
    
    
    
     public static class ProxyManager<TContract>
        {
            internal static ConcurrentDictionary<string, ChannelFactory<TContract>> proxies = new ConcurrentDictionary<string, ChannelFactory<TContract>>(StringComparer.Ordinal);
    
            public static TContract GetProxy()
            {
                var key = typeof(TContract).FullName;
                return proxies.GetOrAdd(key, m => ProxyFactory<TContract>.Create()).CreateChannel();
            }
    
            public static bool RemoveProxy()
            {
                var key = typeof(TContract).FullName;
                ChannelFactory<TContract> proxy;
                return proxies.TryRemove(key, out proxy);
            }
        }
    
      internal class ProxyFactory<TContract>
        {
            static System.ServiceModel.Channels.Binding binding;
    
            public static ChannelFactory<TContract> Create()
            {
                var epa = default(EndpointAddress);
                var fullName = typeof(TContract).FullName.Replace("Contracts", "Facade").Replace(".I", ".");
                var services = System.Configuration.ConfigurationManager.GetSection("system.serviceModel/client") as System.ServiceModel.Configuration.ClientSection;
                var endpoints = services.Endpoints;
                for (var i = 0; i < endpoints.Count; i++)
                {
                    var el = endpoints[i];
                    if (el.Name.Equals(fullName))
                    {
                        epa = new EndpointAddress(el.Address.ToString());
                        var strBinding = el.Binding;
    
                        switch (strBinding)
                        {
                            case "basicHttpBinding":
                                binding = new BasicHttpBinding(strBinding);
                                break;
                            case "wsHttpBinding":
                                binding = new WSHttpBinding(strBinding);
                                break;
                            case "netTcpBinding":
                                binding = new NetTcpBinding(strBinding);
                                break;
                            case "netmsmqBinding":
                                binding = new NetMsmqBinding(strBinding);
                                break;
                            default:
                                throw new NotImplementedException(strBinding + " not implemented.");
                        }
                        break;
                    }
                }
    
                return new ChannelFactory<TContract>(binding, epa);
            }
        }
    
    

    You will call this way:

                var a = Proxy.GetChannel<IService1>().GetData(2);
    

    Just change this line to your naming convertion. 

                var fullName = typeof(TContract).FullName.Replace("Contracts", "Facade").Replace(".I", ".");
    

    My convention is endpoint names are replaced this way: 

    WCFServices.ServiceFacade.Service1 -> WCFServices.ServiceContracts.IService1

    Friday, October 24, 2014 1:30 PM

All replies

  • Hi,

    WCF client proxies generated with ServiceModel Metadata Utility Tool (Svcutil.exe) are derived from ClientBase(Of TChannel). ClientBase(Of TChannel) defines a static CacheSetting property that defines channel factory caching behavior.

    So, it's recommended that you could use the CacheSetting property which has been introduced in WCF 4.5 for cache channel factory:

    http://www.c-sharpcorner.com/UploadFile/54db21/wcf-4-5-new-feature-channel-factory-caching/

    http://www.codeguru.com/columns/experts/channelfactory-caching-in-wcf-4.5-an-insight.htm

    http://msdn.microsoft.com/en-us/library/hh314046(v=vs.110).aspx

    Regards

    Thursday, October 23, 2014 3:31 AM
    Moderator
  • Unfortunately I cannot use the proxy as  there are many services. Any custom caching solution?
    Friday, October 24, 2014 1:24 PM
  • Yes:

      public static class Proxy
        {
            public static T GetChannel<T>()
            {
                return ProxyManager<T>.GetProxy();
            }
        }
    
    
    
     public static class ProxyManager<TContract>
        {
            internal static ConcurrentDictionary<string, ChannelFactory<TContract>> proxies = new ConcurrentDictionary<string, ChannelFactory<TContract>>(StringComparer.Ordinal);
    
            public static TContract GetProxy()
            {
                var key = typeof(TContract).FullName;
                return proxies.GetOrAdd(key, m => ProxyFactory<TContract>.Create()).CreateChannel();
            }
    
            public static bool RemoveProxy()
            {
                var key = typeof(TContract).FullName;
                ChannelFactory<TContract> proxy;
                return proxies.TryRemove(key, out proxy);
            }
        }
    
      internal class ProxyFactory<TContract>
        {
            static System.ServiceModel.Channels.Binding binding;
    
            public static ChannelFactory<TContract> Create()
            {
                var epa = default(EndpointAddress);
                var fullName = typeof(TContract).FullName.Replace("Contracts", "Facade").Replace(".I", ".");
                var services = System.Configuration.ConfigurationManager.GetSection("system.serviceModel/client") as System.ServiceModel.Configuration.ClientSection;
                var endpoints = services.Endpoints;
                for (var i = 0; i < endpoints.Count; i++)
                {
                    var el = endpoints[i];
                    if (el.Name.Equals(fullName))
                    {
                        epa = new EndpointAddress(el.Address.ToString());
                        var strBinding = el.Binding;
    
                        switch (strBinding)
                        {
                            case "basicHttpBinding":
                                binding = new BasicHttpBinding(strBinding);
                                break;
                            case "wsHttpBinding":
                                binding = new WSHttpBinding(strBinding);
                                break;
                            case "netTcpBinding":
                                binding = new NetTcpBinding(strBinding);
                                break;
                            case "netmsmqBinding":
                                binding = new NetMsmqBinding(strBinding);
                                break;
                            default:
                                throw new NotImplementedException(strBinding + " not implemented.");
                        }
                        break;
                    }
                }
    
                return new ChannelFactory<TContract>(binding, epa);
            }
        }
    
    

    You will call this way:

                var a = Proxy.GetChannel<IService1>().GetData(2);
    

    Just change this line to your naming convertion. 

                var fullName = typeof(TContract).FullName.Replace("Contracts", "Facade").Replace(".I", ".");
    

    My convention is endpoint names are replaced this way: 

    WCFServices.ServiceFacade.Service1 -> WCFServices.ServiceContracts.IService1

    Friday, October 24, 2014 1:30 PM
  • You solution worked perfectly but now we are seeing memory leaks in WCF calls, is there any way to dispose the channels automatically.
    Tuesday, December 9, 2014 6:13 AM