• WCF系列教程之WCF客户端异常处理


    本文参考自:http://www.cnblogs.com/wangweimutou/p/4414393.html,纯属读书笔记,加深记忆

    一、简介

    当我们打开WCF基础客户通道,无论是显示打开还是通过调用操作自动打开、使用客户端或者通过对象调用操作,或者关闭基础客户端通道,都会在客户端应用程序中出现异常,WCF是基于网络的通讯服务,错误异常也是要基于消息传递的,在WCF中提供了一个错误消息处理的类FaultException,WCF客户端可以通过它,来接收服务端传递回来的异常信息。

    二、WCF异常类型

    1、意外异常:意外异常包括

    (1)、灾难性故障(OutOfMemoryException)

    (2)、编程错误(ArgumentException(参数异常)和InvalidOperationException(无效的操作异常))

    通常没有有效的方法来处理意外错误,所以通产不应该在调用WCF客户端时捕获这些异常

    2、预期异常:预期异常包括

    (1)、TimeoutException

    (2)、CommunicationException 

    (3)、CommunicationException 的任何派生类

    上面这些异常表明在通信的过程中出现问题,该问题可以通过终止WCF客户端并报告通信故障而得到安全的处理,因为外部因素可能导致任何应用程序中出现这些错误,所以正确的应用程序必须捕获这些异常并在发生异常时进行恢复。

    (4)、如果发生预期异常,客户端或许可以继续使用,或许无法继续使用。若要确定客户端是否仍然可以使用,请检查 State 属性是否为 CommunicationState.Opened。如果此属性仍然处于打开状态,则客户端仍然可以使用。否则,则应中止客户端并释放对其的所有引用。具体参照代码如下:

    if (proxy.State == CommunicationState.Opened){
        Console.WriteLine("CommunicationState is Opened");
     }

    三、代码示例

    工程结构如下图所示:

    1、WCF服务层搭建:新建契约层、服务层、和WCF宿主,添加必须的引用(这里不会的参考本人前面的随笔),配置宿主,生成解决方案,打开Host.exe,开启服务。具体的代码如下:

    ICalculate.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceModel;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace IService
    {
        [ServiceContract]
        public interface ICalculate
        {
            [OperationContract]
            int Add(int a, int b);
    
            [OperationContract]
            int Divide(int value1, int value2);
        }
    }

    IUserInfo.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace IService
    {
        [ServiceContract]
        public interface IUserInfo
        {
            [OperationContract]
            User[] GetInfo(int? id);
        }
    
        [DataContract]
        public class User
        {
            [DataMember]
            public int ID { get; set; }
            [DataMember]
            public string Name { get; set; }
            [DataMember]
            public int Age { get; set; }
            [DataMember]
            public string Nationality { get; set; }  
        }
    }

    注:必须引入System.Runtime.Serialization命名空间,应为User类在被传输时必须是可序列化的,否则将无法传输

    Calculate.cs

    using IService;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.ServiceModel;
    
    namespace Service
    {
        public class Calculate : ICalculate
        {
            public int Add(int a, int b)
            {
                return a + b;
            }
    
    
            public int Divide(int a, int b)
            {
                try
                {
                    return a / b;
                }
                catch (DivideByZeroException) {
                    throw new FaultException("除数不能为0");//FaultException需要引用System.ServiceModel命名空间
                }
            }
        }
    }

    UserInfo.cs

    using IService;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace Service
    {
        public class UserInfo : IUserInfo
        {
            public User[] GetInfo(int? id)
            {
                List<User> Users = new List<User>();
                Users.Add(new User { ID = 1, Name = "张三", Age = 11, Nationality = "China" });
                Users.Add(new User { ID = 2, Name = "李四", Age = 12, Nationality = "English" });
                Users.Add(new User { ID = 3, Name = "王五", Age = 13, Nationality = "American" });
    
                if (id != null)
                {
                    return Users.Where(x => x.ID == id).ToArray();
                }
                else
                {
                    return Users.ToArray();
                }
            }
        }
    }

    Program.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Service;
    using System.ServiceModel;
    
    namespace Host
    {
        class Program
        {
            static void Main(string[] args)
            {
                using (ServiceHost host = new ServiceHost(typeof(Calculate)))
                {
                    host.Opened += delegate { Console.WriteLine("服务已经启动,按任意键终止!"); };
                    host.Open();
                    Console.Read();
                }
            }
        }
    }

    App.Config

    <?xml version="1.0"?>
    <configuration>
      <system.serviceModel>
    
        <services>
          <service name="Service.Calculate" behaviorConfiguration="mexBehavior">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:1234/Calculate/"/>
              </baseAddresses>
            </host>
            <endpoint address="" binding="wsHttpBinding" contract="IService.ICalculate" />
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
          </service>
        </services>
    
        <behaviors>
          <serviceBehaviors>
            <behavior name="mexBehavior">
              <serviceMetadata httpGetEnabled="true"/>
              <serviceDebug includeExceptionDetailInFaults="true"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>

    ok,打开Host.exe

    服务开启成功!

    2、新建一个名为Client的控制台应用程序作为WCF客户端,添加对http://localhost:1234/Calculate/的引用,将命名空间设置为CalculateClientNS,

     

    点击确定,确保添加成功。然后开始编写Program.cs的代码

    (1)、验证除数不能为0的异常抛出

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceModel;
    using System.Text;
    using System.Threading.Tasks;
    using Client.CalculateClientNS;
    
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    CalculateClient calculate = new CalculateClient();
                    Console.WriteLine("1+2={0}", calculate.Add(1, 2));
                    Console.WriteLine("1/0={0}", calculate.Divide(1, 0));
                }
                catch (TimeoutException ex)
                {
                    Console.WriteLine(ex.GetType() + ":" + ex.Message);
                    Console.ReadKey();
                }
                catch (CommunicationException ex)
                {
                    Console.WriteLine(ex.GetType() + ":" + ex.Message);
                    Console.ReadKey();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.GetType() + ":" + ex.Message);
                    Console.ReadKey();
                }
            }
        }
    }

    客户端接收到了服务器返回的除数不能为0的异常,然后抛出。

    (2)、验证通讯超时的异常抛出,原理通过将连接后的时间设置为很小的值,那么服务端的运算肯定来不及,就会抛出超时的信息。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceModel;
    using System.Text;
    using System.Threading.Tasks;
    using Client.CalculateClientNS;
    
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    CalculateClient calculate = new CalculateClient();
                    calculate.InnerChannel.OperationTimeout = TimeSpan.FromSeconds(0.001);//设置下面调用的操作必须在0.001秒内完成.
                    Console.WriteLine("1+2={0}", calculate.Add(1, 2));
                }
                catch (TimeoutException ex)
                {
                    Console.WriteLine(ex.GetType() + ":" + ex.Message);
                    Console.ReadKey();
                }
                catch (CommunicationException ex)
                {
                    Console.WriteLine(ex.GetType() + ":" + ex.Message);
                    Console.ReadKey();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.GetType() + ":" + ex.Message);
                    Console.ReadKey();
                }
            }
        }
    }

    验证通讯超时的异常抛出

    (3)、验证通讯错误的异常抛出

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.ServiceModel;
    using System.Text;
    using System.Threading.Tasks;
    using Client.CalculateClientNS;
    
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    CalculateClient calculate = new CalculateClient();
                    calculate.Abort();//关闭通道
                    Console.WriteLine("1+2={0}", calculate.Add(1, 2));
                }
                catch (TimeoutException ex)
                {
                    Console.WriteLine(ex.GetType() + ":" + ex.Message);
                    Console.ReadKey();
                }
                catch (CommunicationException ex)
                {
                    Console.WriteLine(ex.GetType() + ":" + ex.Message);
                    Console.ReadKey();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.GetType() + ":" + ex.Message);
                    Console.ReadKey();
                }
            }
        }
    }

  • 相关阅读:
    python学习:两个py文件间的函数调用
    python学习:基础概念
    python学习:Windows 下 Python easy_install 的安装
    Python学习:python网址收集
    Nginx模块之Nginx-Ts-Module学习笔记(一)抢险体验
    PHP 文件加密Zend Guard Loader 学习和使用(如何安装ioncube扩展对PHP代码加密)
    OpenResty 扩展库(二)lua-resty-template
    Github 开源项目(二) jsmpeg-vnc
    info replication
    linux下编译make文件报错“/bin/bash^M: 坏的解释器,使用grep快速定位代码位置
  • 原文地址:https://www.cnblogs.com/GreenLeaves/p/6872646.html
Copyright © 2020-2023  润新知