在项目中采用wcf通讯,客户端很多地方调用服务,需要统一的处理超时和通讯异常以及关闭连接。
1.调用尝试和异常捕获
首先,项目中添加一个通用类ServiceDelegate.cs
1 public delegate void UseServiceDelegate<T>(T proxy); 2 3 public static class Service<T> 4 { 5 public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>(""); 6 7 public static void Use(UseServiceDelegate<T> codeBlock) 8 { 9 T proxy = _channelFactory.CreateChannel(); 10 bool success = false; 11 12 13 Exception mostRecentEx = null; 14 for(int i=0; i<5; i++) // Attempt a maximum of 5 times 15 { 16 try 17 { 18 codeBlock(proxy); 19 proxy.Close(); 20 success = true; 21 break; 22 } 23 24 // The following is typically thrown on the client when a channel is terminated due to the server closing the connection. 25 catch (ChannelTerminatedException cte) 26 { 27 mostRecentEx = cte; 28 proxy.Abort(); 29 // delay (backoff) and retry 30 Thread.Sleep(1000 * (i + 1)); 31 } 32 33 // The following is thrown when a remote endpoint could not be found or reached. The endpoint may not be found or 34 // reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable. 35 catch (EndpointNotFoundException enfe) 36 { 37 mostRecentEx = enfe; 38 proxy.Abort(); 39 // delay (backoff) and retry 40 Thread.Sleep(1000 * (i + 1)); 41 } 42 43 // The following exception that is thrown when a server is too busy to accept a message. 44 catch (ServerTooBusyException stbe) 45 { 46 mostRecentEx = stbe; 47 proxy.Abort(); 48 49 // delay (backoff) and retry 50 Thread.Sleep(1000 * (i + 1)); 51 } 52 53 catch(Exception ) 54 { 55 // rethrow any other exception not defined here 56 // You may want to define a custom Exception class to pass information such as failure count, and failure type 57 proxy.Abort(); 58 throw ; 59 } 60 } 61 if (mostRecentEx != null) 62 { 63 proxy.Abort(); 64 throw new Exception("WCF call failed after 5 retries.", mostRecentEx ); 65 } 66 67 } 68 }
然后,这样调用:
无返回值:
Service<IOrderService>.Use(orderService=>
{
orderService.PlaceOrder(request);
}有返回值:
int newOrderId = 0; // need a value for definite assignment
Service<IOrderService>.Use(orderService=>
{
newOrderId = orderService.PlaceOrder(request);
});
Console.WriteLine(newOrderId); // should be updated
2.使用Using方式确保关闭
在客户端扩展一个wcf client的部分类,重写Dispose方法,代码如下:
1 namespace 命名空间要和生成的代码里一致 2 { 3 /// <summary> 4 /// ExtDataClient 5 /// </summary> 6 public partial class *****Client : IDisposable 7 { 8 #region IDisposable implementation 9 10 /// <summary> 11 /// IDisposable.Dispose implementation, calls Dispose(true). 12 /// </summary> 13 void IDisposable.Dispose() 14 { 15 Dispose(true); 16 } 17 18 /// <summary> 19 /// Dispose worker method. Handles graceful shutdown of the 20 /// client even if it is an faulted state. 21 /// </summary> 22 /// <param name="disposing"> 23 /// Are we disposing (alternative 24 /// is to be finalizing) 25 /// </param> 26 protected virtual void Dispose(bool disposing) 27 { 28 if (disposing) 29 { 30 try 31 { 32 if (State != CommunicationState.Faulted) 33 { 34 Close(); 35 } 36 } 37 finally 38 { 39 if (State != CommunicationState.Closed) 40 { 41 Abort(); 42 } 43 } 44 } 45 } 46 47 /// <summary> 48 /// Finalizer. 49 /// </summary> 50 ~*****Client() 51 { 52 Dispose(false); 53 } 54 55 #endregion 56 } 57 }
调用的地方可以直接使用using包起来了
using(****Client client=new ****Client()){//处理逻辑,可以使用try包起来}
3.我自己用到的处理方式,实现一个服务调用单例类,每个服务实现一个调用方法
1 /// <summary> 2 /// 调用SysSvc服务,统一处理TimeoutException和CommunicationException异常 3 /// 用法: 4 /// List<ModuleEO/> list = SvcClient.Instance.SysClientCall(q => q.GetAllModules()); 5 /// </summary> 6 /// <typeparam name="TResult">返回值</typeparam> 7 /// <param name="func">调用的方法</param> 8 /// <returns>泛型返回值</returns> 9 public TResult SysClientCall<TResult>(Func<SysClient, TResult> func) 10 { 11 var client = this.GetSysClient(); 12 try 13 { 14 TResult rec = func.Invoke(client); 15 client.Close(); 16 return rec; 17 } 18 catch (TimeoutException ex) 19 { 20 //服务器超时错误,提示用户即可。 21 client.Abort(); 22 MessageBox.Show("服务器通讯超时,请重新尝试。"); 23 } 24 catch (CommunicationException ex) 25 { 26 //服务器连接通讯异常,提示用户即可。 27 client.Abort(); 28 MessageBox.Show("服务器通讯错误,请重新尝试。"); 29 } 30 catch (Exception ex) 31 { 32 //未处理异常,重新抛出 33 client.Abort(); 34 throw; 35 } 36 return default(TResult); 37 }
参考链接:
http://stackoverflow.com/questions/6130331/how-to-handle-wcf-exceptions-consolidated-list-with-code