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

前端 未结 26 1725
余生分开走
余生分开走 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:32

    What is this?

    This is the CW version of the accepted answer but with (what I consider complete) Exception handling included.

    The accepted answer references this website that is no longer around. To save you trouble, I am including the most relevant parts here. In addition, I modified it slightly to include exception retry handling to handle those pesky network timeouts.

    Simple WCF Client Usage

    Once you generate your client side proxy, this is all you need to implement it.

    Service.Use(orderService=>
    {
      orderService.PlaceOrder(request);
    });
    

    ServiceDelegate.cs

    Add this file to your solution. No changes are needed to this file, unless you want to alter the number of retries or what exceptions you want to handle.

    public delegate void UseServiceDelegate(T proxy);
    
    public static class Service
    {
        public static ChannelFactory _channelFactory = new ChannelFactory(""); 
    
        public static void Use(UseServiceDelegate codeBlock)
        {
            IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
            bool success = false;
    
    
           Exception mostRecentEx = null;
           int millsecondsToSleep = 1000;
    
           for(int i=0; i<5; i++)  // Attempt a maximum of 5 times 
           {
               try
               {
                   codeBlock((T)proxy);
                   proxy.Close();
                   success = true; 
                   break;
               }
    
               // The following is typically thrown on the client when a channel is terminated due to the server closing the connection.
               catch (ChannelTerminatedException cte)
               {
                  mostRecentEx = cte;
                   proxy.Abort();
                   //  delay (backoff) and retry 
                   Thread.Sleep(millsecondsToSleep  * (i + 1)); 
               }
    
               // The following is thrown when a remote endpoint could not be found or reached.  The endpoint may not be found or 
               // reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
               catch (EndpointNotFoundException enfe)
               {
                  mostRecentEx = enfe;
                   proxy.Abort();
                   //  delay (backoff) and retry 
                   Thread.Sleep(millsecondsToSleep * (i + 1)); 
               }
    
               // The following exception that is thrown when a server is too busy to accept a message.
               catch (ServerTooBusyException stbe)
               {
                  mostRecentEx = stbe;
                   proxy.Abort();
    
                   //  delay (backoff) and retry 
                   Thread.Sleep(millsecondsToSleep * (i + 1)); 
               }
               catch (TimeoutException timeoutEx)
               {
                   mostRecentEx = timeoutEx;
                   proxy.Abort();
    
                   //  delay (backoff) and retry 
                   Thread.Sleep(millsecondsToSleep * (i + 1)); 
               } 
               catch (CommunicationException comException)
               {
                   mostRecentEx = comException;
                   proxy.Abort();
    
                   //  delay (backoff) and retry 
                   Thread.Sleep(millsecondsToSleep * (i + 1)); 
               }
               catch(Exception )
               {
                    // rethrow any other exception not defined here
                    // You may want to define a custom Exception class to pass information such as failure count, and failure type
                    proxy.Abort();
                    throw ;  
               }
           }
           if (success == false && mostRecentEx != null) 
           { 
               proxy.Abort();
               throw new Exception("WCF call failed after 5 retries.", mostRecentEx );
           }
    
        }
    }
    

    PS: I've made this post a community wiki. I won't collect "points" from this answer, but prefer you upvote it if you agree with the implementation, or edit it to make it better.

提交回复
热议问题