zoukankan      html  css  js  c++  java
  • 在客户端正确的关闭WCF连接! zt 武胜

    在客户端正确的关闭WCF连接!

    如果你直接将客户端调用Close关闭,或者使用using语句,那你将是个悲剧,这点相信使用WCF的同志都知道的,因为ClientBase类的Close()方法被调用后,实际上是关闭了一个网络会话,并且会抛出异常!CommunicationException和TimeoutException!

    这似乎违反常理,但确实发生了。因为一般来说Close函数都不会抛出异常。这个问题的解决办法是使用Try-Catch语句包含Close()方法,然后再异常处理中使用Abort函数释放资源!

    同样,ClientBase类的IDisposable接口的实现函数Dispose方法中会调用Close函数,使用Reflector查看ClientBase<TChannel> 的代码便知

    所以你使用using语句同样不能正确关闭WCF连接!而我们使用using语句就是为了不管发生什么情况,只要离开作用域之后,就会释放相关资源。而WCF的ClientBase类设计很明显违反了这一观念!简直是坑爹啊!

    解决这一问题网上以后很多方案,首先说说微软的,也许是微软也意识到这一点,所以微软在提供的WCF示例程序中特意包含了一个叫做UsingUsing的示例,名字听起来有点怪

    主要解决的方法是如下的代码

    复制代码
     1 // This method shows the correct way to clean up a client, including catching the
     2         // approprate Exceptions.
     3         static void DemonstrateCleanupWithExceptions()
     4         {
     5             // Create a client
     6             CalculatorClient client = new CalculatorClient();
     7             try
     8             {
     9                 // Demonstrate a successful client call.
    10                 Console.WriteLine("Calling client.Add(0.0, 0.0);");
    11                 double addValue = client.Add(0.0, 0.0);
    12                 Console.WriteLine("        client.Add(0.0, 0.0); returned {0}", addValue);
    13 
    14                 // Demonstrate a failed client call.
    15                 Console.WriteLine("Calling client.Divide(0.0, 0.0);");
    16                 double divideValue = client.Divide(0.0, 0.0);
    17                 Console.WriteLine("        client.Divide(0.0, 0.0); returned {0}", divideValue);
    18 
    19                 // Do a clean shutdown if everything works.  In this sample we do not end up
    20                 // here, but correct code should Close the client if everything was successful.
    21                 Console.WriteLine("Closing the client");
    22                 client.Close();
    23             }
    24             catch (CommunicationException e)
    25             {
    26                 // Because the server suffered an internal server error, it rudely terminated
    27                 // our connection, so we get a CommunicationException.
    28                 Console.WriteLine("Got {0} from Divide.", e.GetType());
    29                 client.Abort();
    30             }
    31             catch (TimeoutException e)
    32             {
    33                 // In this sample we do not end up here, but correct code should catch
    34                 // TimeoutException when calling a client.
    35                 Console.WriteLine("Got {0} from Divide.", e.GetType());
    36                 client.Abort();
    37             }
    38             catch (Exception e)
    39             {
    40                 // In this sample we do not end up here.  It is best practice to clean up the
    41                 // client if some unexpected Exception occurs.
    42                 Console.WriteLine("Got unexpected {0} from Divide, rethrowing.", e.GetType());
    43                 client.Abort();
    44                 throw;
    45             }
    46         }
    复制代码

    其实就是使用try-catch语句捕获关闭时的异常!试想要是每次都这样调用WCF服务将会是多么痛苦的一件事情!网上也有人使用Linq的Expression来解决这一问题

    于是我借用函数式编程的思想,设计了一个使用lambda表达式来解决这一问题的方案!

    关键的函数很简单,一看便知道是我是怎样设计的!

    复制代码
     1 public static class SvcClient
     2     {
     3         public static void Invoke<TClient>(Action<TClient> act)
     4             where TClient : System.ServiceModel.ICommunicationObject, new()
     5         {
     6             TClient client = new TClient();
     7             try
     8             {
     9                 act(client);
    10                 client.Close();
    11             }
    12             catch (System.ServiceModel.CommunicationException)
    13             {
    14                 client.Abort();
    15             }
    16             catch (TimeoutException)
    17             {
    18                 client.Abort();
    19             }
    20             catch (Exception)
    21             {
    22                 client.Abort();
    23                 throw;
    24             }
    25         }
    26     }
    复制代码

    实际上这一设计的思想就是:将所有调用WCF服务的所有代码做为一个函数传入进来,然后我再内部使用try-catch语句包裹整个调用过程,这样就巧妙的将处理关闭连接异常的代码与实际调用过程分离开来!

    函数的使用过程也比较方便

    1 SvcClient.Invoke<Service1Client>(client =>
    2 {
    3   //在此处添加调用WCF的代码
    4 });

    代码看起来比较简洁优美,个人比较满意,而且不用再担心调用结束后不能正确关闭WCF连接,资源不能正确释放的问题了!

  • 相关阅读:
    CF547D Mike and Fish
    CF147B Smile House
    [BJOI2017]树的难题
    AT2306 Rearranging
    复利计算器--单元测试
    操作系统 实验1 命令解释程序的编写
    个人项目耗时对比记录表
    复利计算器3.0
    0320记《构建之法》读后感
    复利计算实验总结
  • 原文地址:https://www.cnblogs.com/zeroone/p/3133425.html
Copyright © 2011-2022 走看看