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

WCF中的异常的更多相关文章

  1. WCF学习之旅—WCF中传统的异常处理(十六)

    WCF中的异常处理 在软件开发过程中,不可能没有异常的出现,所以在开发过程中,对不可预知的异常进行解决时,异常处理显得尤为重要.对于一般的.NET系统来说,我们简单地借助try/catch可以很容易地 ...

  2. WCF初探-26:WCF中的会话

    理解WCF中的会话机制 在WCF应用程序中,会话将一组消息相互关联,从而形成对话.会话”是在两个终结点之间发送的所有消息的一种相互关系.当某个服务协定指定它需要会话时,该协定会指定所有调用(即,支持调 ...

  3. <转>WCF中出现死锁或者超时

    WCF回调中的死锁 一.服务器端死锁 对于如下服务: [ServiceContract(CallbackContract = typeof(INotify))] public class Downlo ...

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

    一.引言 在前面的WCF服务中,它都要求服务与客户端两端都必须启动并且运行,从而实现彼此间的交互.然而,还有相当多的情况希望一个面向服务的应用中拥有离线交互的能力.WCF通过服务队列的方法来支持客户端 ...

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

    一.引言 由前面几篇博文我们知道,WCF是微软基于SOA建立的一套在分布式环境中各个相对独立的应用进行交流(Communication)的框架,它实现了最新的基于WS-*规范.按照SOA的原则,相对独 ...

  6. 我的WCF之旅(3):在WCF中实现双工通信

    双工(Duplex)模式的消息交换方式体现在消息交换过程中,参与的双方均可以向对方发送消息.基于双工MEP消息交换可以看成是多个基本模式下(比如请求-回复模式和单项模式)消息交换的组合.双工MEP又具 ...

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

    原文:WCF技术剖析之十一:异步操作在WCF中的应用(上篇) 按照操作执行所需的资源类型,我们可以将操作分为CPU绑定型(CPU Bound)操作和I/O绑定型(I/O Bound)操作.对于前者,操 ...

  8. WCF中队列服务详解

    WCF中队列服务详解 一.引言 在前面的WCF服务中,它都要求服务与客户端两端都必须启动并且运行,从而实现彼此间的交互.然而,还有相当多的情况希望一个面向服务的应用中拥有离线交互的能力.WCF通过服务 ...

  9. WCF 服务端异常封装

    通常WCF服务端异常的详细信息只有在调试环境下才暴露出来,但我目前有需求需要将一部分异常的详细信息传递到客户端,又需要保证一定的安全性. 最简单的办法当然是在服务端将异常捕获后,序列化传给客户端,但这 ...

随机推荐

  1. 纸壳CMS替换默认实现

    简介 纸壳CMS是一个开源免费的可视化内容管理建站系统,拖拽就可以轻松建网站. GitHub: http://github.com/SeriaWei/ZKEACMS 纸壳CMS在设计上使用的是ASP. ...

  2. 单线程任务 Task.Factory.StartNew 封装

    代码: using log4net; using SunCreate.CombatPlatform.Security; using System; using System.Collections.G ...

  3. Http请求基本方法

    1.Http请求基本方法 /// <summary> /// Http请求基本方法 /// </summary> /// <param name="conten ...

  4. 第三节:使用Log4net和过滤器记录异常信息,返回异常给前端

    上次面试,遇到,在项目中如何处理业务异常和代码异常,使用txt记录异常信息后,如何直接区分出异常的类型,异常怎么分类处理,希望大家能帮我提出宝贵的意见,完善处理异常, 统一返回参数 public cl ...

  5. c# 字符串去掉两端空格,并且将字符串中多个空格替换成一个空格

    字符串去掉两端空格,并且将字符串中多个空格替换成一个空格: 主要还是考察使用字符串的方法: trim(); 去掉字符串两端空格 split(); 切割 string.join(); 连接 class ...

  6. GSS1 - Can you answer these queries I(线段树)

    前言 线段树菜鸡报告,stO ZCDHJ Orz,GSS基本上都切完了. Solution 考虑一下用线段树维护一段区间左边连续的Max,右边的连续Max,中间的连续Max还有总和,发现这些东西可以相 ...

  7. Day4 作业

    a=[1,2,3,6,"dfs",100]s=a[-1:]print (s)答案:[100] s=a[-1:0:-1]print(s) 答案:[100, 'dfs', 6, 3, ...

  8. 网络请求 get 请求时, 如果参数中的字符带有+号

    网络请求 get 请求时, 如果参数中的字符带有+号, 今天前端在调用我的API时, 发现有个参数一直没法通过我后台的验证, 但是在前端查看时, 该参数结构又没有什么异常, 又是一番查找, 直到在后端 ...

  9. Python面向对象(特殊成员)

    day25 __init__     类()自动执行     __del__     __call__     对象()  类()() 自动执行     __int__      int(对象)    ...

  10. Python面向对象(类的成员之方法)

    day24 类的成员之方法 - 普通方法,保存在类中,由对象来调用,self > 对象 - 静态方法,保存在类中,由类直接调用 - 类方法,保存在类中,由类直接调用,cls > 当前类 c ...