WCF中的异常

   一、考虑到安全因素,为了避免将服务端的异常发送给客户端。默认情况下,服务端出现异常会对异常屏蔽处理后,再发送到客户端。所以客户端捕捉到的异常都是同一个FaultException异常。

例如在服务端直接产生一个空引用异常,客户端捕获到的是上述异常。

服务端:

 class Program
    {
        static void Main(string[] args)
        {
            ServiceHost host = new ServiceHost(typeof(SayHello));
            host.AddServiceEndpoint(typeof(ISayHello), new WSHttpBinding(), "http://localhost:4216");
            host.Opened += delegate { Console.WriteLine("Service Start!"); };
            host.Open();
            Console.ReadLine();
        }
    }
    [ServiceContract]
    public interface ISayHello
    {
        [OperationContract]
        void Say();
    }

    public class SayHello : ISayHello
    {
        public void Say()
        {
            string name = null;
            Console.Write("Hello {0}", name.Length);
        }
    }

客户端:

 class Program
    {
        static void Main(string[] args)
        {
          ISayHello ClientChannel =  ChannelFactory<ISayHello>.CreateChannel(new WSHttpBinding(), new EndpointAddress("http://localhost:4216"));
          try
          {
              ClientChannel.Say();
          }
          catch (Exception ex)
          {
              Console.WriteLine(ex.Message);
              Console.WriteLine(ex.StackTrace);
          }
        }
    }

 二、可通过配置ServiceDebugBehavior将IncludeExceptionDetailInFaults,将其置为true。则服务端会将异常原封不动的传递到客户端,该配置默认为false。

 [ServiceBehavior(IncludeExceptionDetailInFaults=true)]
    public class SayHello : ISayHello
    {
        public void Say()
        {
            string name = null;
            Console.Write("Hello {0}", name.Length);
        }
    }

客户端捕捉到空引用异常。

三、自定义异常信息

1.直接通过FaultException构造函数,构造异常。

    [ServiceBehavior(IncludeExceptionDetailInFaults=true)]
    public class SayHello : ISayHello
    {
        public void Say()
        {
            throw new FaultException("自定义异常");
        }
    }

2.通过FaultException<TDetail>构造异常。

TDetail是一个可序列化的数据结构,如下面定义的myException。需要注意的是在操作契约上需要加一个错误契约,   [FaultContract(typeof(myException))]。

   [ServiceContract]
    public interface ISayHello
    {
        [OperationContract]
        [FaultContract(typeof(myException))]
        void Say();
    }
    [ServiceBehavior(IncludeExceptionDetailInFaults=true)]
    public class SayHello : ISayHello
    {
        public void Say()
        {
            myException ex = new myException
            {
                Message = "自定义异常",
                OperatorMethodName = "SayHello:Say()"
            };
            throw new FaultException<myException>(ex, ex.Message);
        }
    }

    [DataContract]
    public class myException
    {
        [DataMember]
        public string Message;
        [DataMember]
        public string OperatorMethodName;
    }

客户端:

 class Program
    {
        static void Main(string[] args)
        {
            ISayHello ClientChannel = ChannelFactory<ISayHello>.CreateChannel(new WSHttpBinding(), new EndpointAddress("http://localhost:4216"));
          try
          {
              ClientChannel.Say();
          }
          catch (Exception ex)
          {
              myException myex = (ex as FaultException<myException>).Detail;
              Console.WriteLine(myex.Message);
              Console.WriteLine(myex.OperatorMethodName);
          }
        }
    }

使用错误契约需要注意的地方:

(1)不能再同一个操作方法上声明相同的细节类型。如下所示:

    [ServiceContract]
    public interface ISayHello
    {
        [OperationContract]
        [FaultContract(typeof(myException))]
        [FaultContract(typeof(myException))]
        void Say();
    }

(2)错误契约上的细节类型不能等效。

    [ServiceContract]
    public interface ISayHello
    {
        [OperationContract]
        [FaultContract(typeof(myException),Name="PersonalException",Namespace="www.cnblogs.cn/lh218")]
        [FaultContract(typeof(myError), Name = "PersonalException", Namespace = "www.cnblogs.cn/lh218")]
        void Say();
    }

四、可以指定异常的序列化方式

默认的情况下异常消息还DataContractSerializer序列化的。可以通过XmlSerializerFormat的SupportFaults,指定使用XmlSerializer序列化异常消息。

   [ServiceContract]
    public interface ISayHello
    {
        [OperationContract]
        [FaultContract(typeof(myException))]
        [XmlSerializerFormat(SupportFaults=true)]
        void Say();
    }

 五、错误消息的结构

由5部分组成

(1)FaultCode,可以看出是对异常消息的分类。结点内部的Value表示错误类型,SubCode表示错误子代码。

(2)FaultReason表示错误原因,内部有一个FaultReasonText集合,FaultReasonText支持全球化语言描述。

(3)FaultNode元素,表示在SOAP消息路由过程中产生异常的结点。

(4)FaultRole表示处理消息时所担当的角色。

(5)FaultDetail 即之前描述的错误细节。

下面代码讲创建一个错误消息:

using System.Xml;
using System.Xml.Serialization;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Runtime.Serialization;
using System.ServiceModel.Channels;
namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            FaultCode subCode = new FaultCode("lh218", "www.cnblogs.com/lh218");
            FaultCode code = new FaultCode("myFault", subCode);
            var text1=new FaultReasonText("异常消息","zh-CN");
            var text2=new FaultReasonText("Exception Message","en-US");
            FaultReason reason=new FaultReason(new FaultReasonText[]{text1,text2});
            myException exDetail = new myException
            {
                Message = "自定义异常细节",
                OperatorMethodName = "myException"
            };
            MessageFault fault = MessageFault.CreateFault(code, reason, exDetail, new DataContractSerializer(typeof(myException)), "lhActor","lhNode");
            Message msg = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, fault, "http://myaction");
            Write(msg, @"D://1.txt");
            Console.ReadLine();
        }

        public static  void Write(Message msg,string path)
        {
            using (XmlTextWriter writer = new XmlTextWriter(path,Encoding.UTF8))
            {
                writer.Formatting = Formatting.Indented;
                msg.WriteMessage(writer);
            }
        }
    }
}

消息为:

<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://myaction</a:Action>
  </s:Header>
  <s:Body>
    <s:Fault>
      <s:Code>
        <s:Value>s:myFault</s:Value>
        <s:Subcode>
          <s:Value xmlns:a="www.cnblogs.com/lh218">a:lh218</s:Value>
        </s:Subcode>
      </s:Code>
      <s:Reason>
        <s:Text xml:lang="zh-CN">异常消息</s:Text>
        <s:Text xml:lang="en-US">Exception Message</s:Text>
      </s:Reason>
      <s:Node>lhNode</s:Node>
      <s:Role>lhActor</s:Role>
      <s:Detail>
        <PersonalException xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="www.cnblogs.com/lh218">
          <Message>自定义异常细节</Message>
          <OperatorMethodName>myException</OperatorMethodName>
        </PersonalException>
      </s:Detail>
    </s:Fault>
  </s:Body>
</s:Envelope>

 六、异常与消息之间的转换关系

如上图所示,MessageFault是FaultException和Message直接的中转对象。

先看Server端:

FaultException ==》MessageFault转换方法:FaultException对象可以调用CreateMessageFault创建MessageFault对象。

public virtual MessageFault CreateMessageFault();

MessageFault   ==》 Message:Message调用CreateMessage创建,传入MessageFault参数。

   public static Message CreateMessage(MessageVersion version, MessageFault fault, string action);

Client端:

Message==>MessageFault:MessageFault类型内部的CreateFault方法可以提取异常消息中的MessageFault

     public static MessageFault CreateFault(Message message, int maxBufferSize);

  MessageFault ==》FaultException:FaultException类型提供两个静态方法创建FaultException。

   public static FaultException CreateFault(MessageFault messageFault, params Type[] faultDetailTypes);

    public static FaultException CreateFault(MessageFault messageFault, string action, params Type[] faultDetailTypes);

时间: 2024-08-08 05:13:53

WCF中的异常的相关文章

跟我一起学WCF(11)——WCF中队列服务详解

一.引言 在前面的WCF服务中,它都要求服务与客户端两端都必须启动并且运行,从而实现彼此间的交互.然而,还有相当多的情况希望一个面向服务的应用中拥有离线交互的能力.WCF通过服务队列的方法来支持客户端和服务之间的离线工作,客户端将消息发送到一个队列中,再由服务对它们进行处理.下面让我们具体看看WCF中的队列服务. 二.WCF队列服务的优势 在介绍WCF队列服务之前,首先需要了解微软消息队列(MSMQ).MSMQ是在多个不同应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布在同一台机器

&lt;转&gt;WCF中出现死锁或者超时

WCF回调中的死锁 一.服务器端死锁 对于如下服务: [ServiceContract(CallbackContract = typeof(INotify))] public class DownloadService { [OperationContract] public void Download() { //开始下载操作 //..... //通知下载完成 var callback = OperationContext.Current.GetCallbackChannel<INotify>

wcf中的使用全双工通信(转)

wcf中的使用全双工通信 wcf中的契约通信默认是请求恢复的方式,当客户端发出请求后,一直到服务端回复时,才可以继续执行下面的代码. 除了使用请求应答方式的通信外,还可以使用全双工.下面给出例子: 1.添加一个wcf类库 2.在服务契约添加如下一个片段 [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples", SessionMode = SessionMode.Required,         Call

WCF初探-26:WCF中的会话

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

跟我一起学WCF(8)——WCF中Session、实例管理详解

一.引言 由前面几篇博文我们知道,WCF是微软基于SOA建立的一套在分布式环境中各个相对独立的应用进行交流(Communication)的框架,它实现了最新的基于WS-*规范.按照SOA的原则,相对独自的业务逻辑以Service的形式进行封装,调用者通过消息(Messaging)的方式来调用服务.对于承载某个业务功能实现的服务应该具有上下文(Context)无关性,意思就是说构造服务的操作(Operation)不应该绑定到具体的调用上下文,对于任何的调用,具有什么的样输入就会对应怎样的输出.因为

WCF中自定义消息编码器:压缩编码器的使用

原文:WCF中自定义消息编码器:压缩编码器的使用 通过抓包知道WCF在提交.返回数据的时候大多使用XML进行数据交互,如果返回DataTable那么这些数据将变得很大,通过查询找到一个对数据压缩的方法: http://msdn.microsoft.com/zh-cn/library/ms751458(v=vs.110).aspx 新增项目GZipEncoder,GzipEncoder中增加三个文件 : GZipMessageEncoderFactory.cs using System; usin

真实代理(RealProxy)在WCF中的运用

在WCF中,当我们在调用服务端的方法时,一般有两点需要考虑:1.捕获服务端的异常信息,记录日志:2.及时关闭会话信道,当调用超时或调用失败时及时中断会话信道.我们一般会像下面这样处理(以CalculatorService为例): using (ChannelFactory<ICalculatorService> channelFactory = new ChannelFactory<ICalculatorService>("CalculatorService")

WCF技术剖析之十一:异步操作在WCF中的应用(上篇)

原文:WCF技术剖析之十一:异步操作在WCF中的应用(上篇) 按照操作执行所需的资源类型,我们可以将操作分为CPU绑定型(CPU Bound)操作和I/O绑定型(I/O Bound)操作.对于前者,操作的执行主要利用CPU进行密集的计算,而对于后者,大部分的操作处理时间花在I/O操作处理,比如访问数据库.文件系统.网络资源等.对于I/O绑定型操作,我们可以充分利用多线程的机制,让多个操作在自己的线程并发执行,从而提高系统性能和响应能力.服务调用就是典型的I/O绑定型操作,所以多线程在服务调用中具

Laravel 5.4 中的异常处理器和HTTP异常处理实例教程

错误和异常是处理程序开发中不可回避的议题,在本地开发中我们往往希望能捕获程序抛出的异常并将其显示打印出来,以便直观的知道程序在哪里出了问题并予以解决,而在线上环境我们不希望将程序错误或异常显示在浏览器中(出于安全考虑),这个时候我们仍然要捕获异常,只不过不是显示到浏览器中,而是记录到日志中,方便日后排查问题. 百牛信息技术bainiu.ltd整理发布于博客园 Laravel当然支持PHP原生的错误和异常处理,但是在此基础上进行了一些封装处理,从而更方便在不同开发环境切换以及对错误和异常的处理.