What is the best workaround for the WCF client `using` block issue?

前端 未结 26 1598
余生分开走
余生分开走 2020-11-22 00:03

I like instantiating my WCF service clients within a using block as it\'s pretty much the standard way to use resources that implement IDisposable:

26条回答
  •  南笙
    南笙 (楼主)
    2020-11-22 00:17

    Below is an enhanced version of the source from the question and extended to cache multiple channel factories and attempt to look up the endpoint in the configuration file by contract name.

    It uses .NET 4 (specifically: contravariance, LINQ, var):

    /// 
    /// Delegate type of the service method to perform.
    /// 
    /// The service proxy.
    /// The type of service to use.
    internal delegate void UseServiceDelegate(T proxy);
    
    /// 
    /// Wraps using a WCF service.
    /// 
    /// The type of service to use.
    internal static class Service
    {
        /// 
        /// A dictionary to hold looked-up endpoint names.
        /// 
        private static readonly IDictionary cachedEndpointNames = new Dictionary();
    
        /// 
        /// A dictionary to hold created channel factories.
        /// 
        private static readonly IDictionary> cachedFactories =
            new Dictionary>();
    
        /// 
        /// Uses the specified code block.
        /// 
        /// The code block.
        internal static void Use(UseServiceDelegate codeBlock)
        {
            var factory = GetChannelFactory();
            var proxy = (IClientChannel)factory.CreateChannel();
            var success = false;
    
            try
            {
                using (proxy)
                {
                    codeBlock((T)proxy);
                }
    
                success = true;
            }
            finally
            {
                if (!success)
                {
                    proxy.Abort();
                }
            }
        }
    
        /// 
        /// Gets the channel factory.
        /// 
        /// The channel factory.
        private static ChannelFactory GetChannelFactory()
        {
            lock (cachedFactories)
            {
                var endpointName = GetEndpointName();
    
                if (cachedFactories.ContainsKey(endpointName))
                {
                    return cachedFactories[endpointName];
                }
    
                var factory = new ChannelFactory(endpointName);
    
                cachedFactories.Add(endpointName, factory);
                return factory;
            }
        }
    
        /// 
        /// Gets the name of the endpoint.
        /// 
        /// The name of the endpoint.
        private static string GetEndpointName()
        {
            var type = typeof(T);
            var fullName = type.FullName;
    
            lock (cachedFactories)
            {
                if (cachedEndpointNames.ContainsKey(type))
                {
                    return cachedEndpointNames[type];
                }
    
                var serviceModel = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).SectionGroups["system.serviceModel"] as ServiceModelSectionGroup;
    
                if ((serviceModel != null) && !string.IsNullOrEmpty(fullName))
                {
                    foreach (var endpointName in serviceModel.Client.Endpoints.Cast().Where(endpoint => fullName.EndsWith(endpoint.Contract)).Select(endpoint => endpoint.Name))
                    {
                        cachedEndpointNames.Add(type, endpointName);
                        return endpointName;
                    }
                }
            }
    
            throw new InvalidOperationException("Could not find endpoint element for type '" + fullName + "' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element.");
        }
    }
    

提交回复
热议问题