WCF初探-20:WCF错误协定

WCF错误协定概述

  • 在所有托管应用程序中,处理错误由 Exception 对象表示。 在基于 SOAP 的应用程序(如 WCF 应用程序)中,服务方法使用 SOAP 错误消息来传递处理错误信息。 SOAP 错误是包括在服务操作元数据中的消息类型,因此会创建一个错误协定,客户端可使用该协定来使操作更加可靠或更具交互性。 此外,由于 SOAP 错误在客户端以 XML 格式表示,这是一种任何 SOAP 平台上的客户端都可以使用的具有极好的互操作性的类型系统,可增加 WCF 应用程序的适用范围。
  • 由于 WCF 应用程序在两种类型的错误系统下都可运行,因此发送到客户端的任何托管异常信息都必须在服务上从异常转换为 SOAP 错误,并在 WCF 客户端中从 SOAP 错误转换为错误异常。 对于双工客户端,客户端协定还可以将 SOAP 错误发送回服务。 在任一种情况下,您都可以使用默认的服务异常行为,或者可以显式控制是否(以及如何)将异常映射到错误消息。
  • 可以发送两种类型的 SOAP 错误:已声明的和未声明的。 已声明的 SOAP 错误是指其中的某个操作具有 System.ServiceModel.FaultContractAttribute 属性(用于指定自定义 SOAP 错误类型)的错误。 未声明的 SOAP 错误是在操作的协定中没有指定的错误。

创建错误协定

  • 要实现错误协定传递到客户端,首先需要将将 ServiceBehaviorAttribute.IncludeExceptionDetailInFaults 或 ServiceDebugBehavior.IncludeExceptionDetailInFaults 设置为 true(可以在服务配置文件中指定)。
  • 定义错误协定时,我们通常是自定义错误信息显示。通常我们将需要显示的错误信息定义为数据协定,再使用FaultContractAttribute在操作协定上进行标记类型为哪一种数据协定的错误。
  • 操作过程中发生托管异常时将引发 FaultException<TDetail>(此处类型参数为可序列化的错误信息)。 WCF 客户端应用程序呈现的 SOAP 错误类型与客户端实现中引发的类型相同,即FaultException<TDetail>(此处类型参数为可序列化的错误信息)。 FaultContractAttribute 只能用来为双向服务操作和异步操作对指定 SOAP 错误;单向操作并不支持 SOAP 错误,因而不支持 FaultContractAttribute。

WCF错误协定示例

  • 解决方法结构如下:

  

  • 工程结构说明:
  1. Service:类库程序,WCF服务端程序。在服务协定接口ISampleService.cs中定义了数据协定FaultMessage来显示错误的时间和信息,在操作协定SampleMethod上,我们用FaultContract来标记错误协定的类型为FaultMessage。在实现操作协定方法SampleMethod中,我们可以利用FaultException<FaultMessage>来自定义错误,抛出自定义异常信息。在客户端利用FaultException<FaultMessage>中的Detail可以获取包含详细错误信息的对象。ISampleService.cs的代码如下:
using System.ServiceModel;
using System.Runtime.Serialization;

namespace Service
{
    [ServiceContract]
    public interface ISampleService
    {
        [OperationContract]
        [FaultContract(typeof(FaultMessage))]
        string SampleMethod(string msg);
    }

    [DataContract]
    public class FaultMessage
    {
        private string _errorTime;
        private string _errorMessage;

        [DataMember]
        public string ErrorTime
        {
            get { return this._errorTime; }
            set { this._errorTime = value; }
        }

        [DataMember]
        public string ErrorMessage
        {
            get { return this._errorMessage; }
            set { this._errorMessage = value; }
        }

        public FaultMessage(string time,string message)
        {
            this._errorTime = time;
            this._errorMessage = message;
        }
    }
}

  SampleService.cs的代码如下:

using System.ServiceModel;

namespace Service
{
    public class SampleService :ISampleService
    {
        public string SampleMethod(string msg)
        {
            if (msg.Length < 10)
            {
                return "输入的字符串为" + msg;
            }
            else
            {
                throw new FaultException<FaultMessage>(
                    new FaultMessage("错误时间:" + System.DateTime.Now.ToString(), "输入的【" + msg + "】字符串大于10个字符"));
            }
        }
    }
}

  

  2.  Host:控制台应用程序,服务承载程序。添加对程序集Service的引用,完成以下代码,寄宿服务。Program.cs代码如下:

  

using System;
using System.ServiceModel;
using Service;

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

  App.config代码如下:

  

<?xml version="1.0"?>
<configuration>
    <system.serviceModel>

        <services>
            <service name="Service.SampleService" behaviorConfiguration="mexBehavior">
                <host>
                    <baseAddresses>
                        <add baseAddress="http://localhost:1234/SampleService/"/>
                    </baseAddresses>
                </host>
                <endpoint address="" binding="wsHttpBinding" contract="Service.ISampleService" />
                <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>

  我们通过svcutil.exe工具生成客户端代理类和客户端的配置文件

  svcutil.exe是一个命令行工具,位于路径C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin下,我们可以通过命令行运行该工具生成客户端代理类

  • 在运行中输入cmd打开命令行,输入 cd C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin
  • 输入svcutil.exe /out:f:\ SampleServiceClient.cs /config:f:\App.config http://localhost:1234/ SampleService

  3.  Client:控制台应用程序,客户端调用程序。将生成的UserInfoClient.cs和App.config复制到Client的工程目录下,完成客户端调用代码。Program.cs的代码如下:

using System;
using System.ServiceModel;
using Service;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            SampleServiceClient proxy = new SampleServiceClient();
            try
            {
                Console.WriteLine(proxy.SampleMethod("WCF"));
                Console.WriteLine(proxy.SampleMethod("Windows Communication Foundation"));
            }
            catch (FaultException<FaultMessage> ex)
            {
                Console.WriteLine(ex.Detail.ErrorTime+"\n"+ex.Detail.ErrorMessage);
            }
            finally
            {
                Console.Read();
            }

        }
    }
}

  程序运行结果如下:

  

总结

  • 通常我们在服务端通过FaultException抛出异常信息,然后就可以在客户端进行处理,即使我们不加FaultContract特性。参照:WCF初探-12:WCF客户端异常处理
  • 我们也可以通过添加ServiceBehavior特性,将服务的IncludeExceptionDetailInFaults设置为true(默认为 false),客户端也可以捕获抛出的非FaultException异常信息,但该异常仍然会导致通道出现错误。
  • 在本示例中,我们实现了错误协定的自定义错误信息操作。其中最重要的FaultException<TDetail>,通过TDetail类型,我们可以把自定义的数据协定错误信息在服务端客户端进行序列化和反序列化,最终实现SOAP消息的错误信息的传递。
时间: 2024-08-07 08:23:43

WCF初探-20:WCF错误协定的相关文章

WCF初探-15:WCF操作协定

前言: 在前面的文章中,我们定义服务协定时,在它的操作方法上都会加上OperationContract特性,此特性属于OperationContractAttribute 类,将OperationContract应用于方法,以指示该方法实现作为服务协定(由 ServiceContractAttribute 属性指定)一部分的服务操作.OperationContractAttribute 属性声明方法是服务协定中的操作. 只有具有 OperationContractAttribute 属性的方法可

WCF初探-14:WCF服务协定

前言: 在前面的文章中,我们定义的服务协定上都会有一个ServiceContract的特性来修饰,这是因为服务契约的实现要靠ServiceContractAttribute 属性定义,然后使用一个或多个类(或接口)方法中的 OperationContractAttribute 属性定义协定的服务操作. 实现服务协定后并将其与WCF 绑定和 EndpointAddress 对象一起使用时,此服务协定将公开以供客户端使用. 公开的信息由 ServiceContractAttribute 表示,其接口

【WCF】错误协定声明

在上一篇烂文中,老周给大伙伴们介绍了 IErrorHandler 接口的使用,今天,老周补充一个错误处理的知识点——错误协定. 错误协定与IErrorHandler接口不同,大伙伴们应该记得,上回我们是把自己实现IErrorHandler接口的类型添加到ChannelDispatcher中的,也就是说,IErrorHandler处理的是通道层的错误,它可以捕捉到多个服务操作上发生的错误.而错误协定是面向协定层的,它是通过 FaultContractAttribute 来声明的,这个特性在上一篇文

WCF初探-22:WCF中使用Message类(上)

前言 从我们学习WCF以来,就一直强调WCF是基于消息的通信机制.但是由于WCF给我们做了高级封装,以至于我们在使用WCF的时候很少了解到消息的内部机制.由于WCF的架构的可扩展性,针对一些特殊情况,WCF为我们提供了Message类来深度定制消息结构,以便我们拓展WCF的通信机制. 在之前的文章中,我们针对一些常用的WCF传递数据的方式进行了说明,比如数据协定和消息协定等.他们传递的数据最终都会转化为消息的实例.具体参照:        WCF初探-16:WCF数据协定之基础知识       

WCF初探-10:WCF客户端调用服务

创建WCF 服务客户端应用程序需要执行下列步骤: 获取服务终结点的服务协定.绑定以及地址信息 使用该信息创建 WCF 客户端 调用操作 关闭该 WCF 客户端对象 WCF客户端调用服务存在以下特点: 服务和客户端使用托管属性.接口和方法对协定进行建模. 若要连接客户端应用程序中的服务,则需要获取该服务协定的类型信息.通常,我们使用Svcutil.exe(ServiceModel Metadata Utility Tool)来完成,也可以直接在客户端项目上引用服务地址完成.它们会从服务中下载元数据

WCF初探-1:认识WCF

1.WCF是什么? WindowsCommunication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,它是.NET框架的一部分,由.NET Framework 3.0开始引入,与Windows Presentation Foundation及 Windows Workflow Foundation并行为新一代Windows操作系统以及WinFX的三个重大应用程序开发类库. 在.NETFramework 2.0以及前版本中,微软发展了Web Service(SO

WCF初探-26:WCF中的会话

理解WCF中的会话机制 在WCF应用程序中,会话将一组消息相互关联,从而形成对话.会话”是在两个终结点之间发送的所有消息的一种相互关系.当某个服务协定指定它需要会话时,该协定会指定所有调用(即,支持调用的基础消息交换)必须是同一对话的一部分.如果某个协定指定它允许使用会话但不要求使用会话,则客户端可以进行连接,并选择建立会话或不建立会话.如果会话结束,然后在同一个通道上发送消息,将会引发异常. WCF中的会话机制通过设置服务协定(ServiceContract)上的SessionMode的枚举值

WCF初探-13:WCF客户端为双工服务创建回调对象

前言: 在WCF初探-5:WCF消息交换模式之双工通讯(Duplex)博文中,我讲解了双工通信服务的一个应用场景,即订阅和发布模式,这一篇,我将通过一个消息发送的例子讲解一下WCF客户端如何为双工服务创建回调对象. 双工服务指定一个回调协定,客户端应用程序必须实现该协定以便提供一个该服务能够根据协定要求调用的回调对象.虽然回调对象不是完整的服务(例如,您无法使用回调对象启动一个通道),但是为了实现和配置,这些回调对象可以被视为一种服务. 双工服务的客户端必须: 实现一个回调协定类. 创建回调协定

解决WCF调用时出现错误:“创建MTOM消息读取器时出错”

如题,查询一个数据集, 存储过程返回如:select * from B 中间层定义  public DataSet GetTable(string 查询条件); 客户端定义  DataSet ds = wcfClient.GetTable("") 以前一直正常着,查询也很快速,这两天不知修改到哪了,所有的查询如果返回记录较大时(100条左右),客户端就会出现服务端返回的异常错误"创建MTOM消息读取器时出错" 客户端 app.config 配置如下 <syst