WCF中wcf data serviceContract和MessageContract的区别

.net4.0中,wcf的数据契约上可以不用写DataContract和DataMember标签了么?
[问题点数:40分,结帖人zengjd]
.net4.0中,wcf的数据契约上可以不用写DataContract和DataMember标签了么?
[问题点数:40分,结帖人zengjd]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
相关帖子推荐:
2013年7月 MS-SQL Server大版内专家分月排行榜第一2009年3月 Oracle大版内专家分月排行榜第一2009年2月 Oracle大版内专家分月排行榜第一
2013年9月 MS-SQL Server大版内专家分月排行榜第二2013年8月 MS-SQL Server大版内专家分月排行榜第二2009年4月 Oracle大版内专家分月排行榜第二2009年1月 Oracle大版内专家分月排行榜第二2004年10月 MS-SQL Server大版内专家分月排行榜第二
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。[爱心链接:]在本篇文章中,我们将讨论WCF四大契约(服务契约、数据契约、消息契约和错误契约)之一的消息契约(Message Contract)。服务契约关注于对服务操作的描述,数据契约关注于对于数据结构和格式的描述,而消息契约关注的是类型成员与消息元素的匹配关系。
我们知道只有可序列化的对象才能通过服务调用在客户端和服务端之间进行传递。到目前为止,我们知道的可序列化类型有两种:一种是应用了特性或者实现了接口的类型;另一种是数据契约对象。对于基于这两种类型的服务操作,客户端通过将输入参数格式化成请求消息,输入参数全部内容作为有效负载置于消息的主体中;同样地,服务操作的执行结果被序列化后作为回复消息的主体。
在一些情况下,具有这样的要求:当序列化一个对象并生成消息的时候,希望将部分数据成员作为SOAP的报头,部分作为消息的主体。比如说,我们有一个服务操作采用流的方式进行文件的上载,除了以流的方式传输以二进制表示的文件内容外,还需要传输一个额外的基于文件属性的信息,比如文件格式、文件大小等。一般的做法是将传输文件内容的流作为SOAP的主体,将其属性内容作为SOAP的报头进行传递。这样的功能,可以通过定义消息契约来实现。
一、 消息契约的定义 消息契约和数据契约一样,都是定义在数据(而不是功能)类型上。不过数据契约旨在定义数据的结构(将数据类型与XSD进行匹配),而消息契约则更多地关注于数据的成员具体在SOAP消息中的表示。消息契约通过以下3个特性进行定义:、、。MessageContractAttribute应用于类型上,MessageHeaderAttribute和MessageBodyMemberAttribute则应用于属性或者字段成员上,表明相应的数据成员是一个基于SOAP报头的成员还是SOAP主体的成员。先来简单介绍一下这3个特性:
1、MessageContractAttribute 通过在一个类或者结构(Struct)上应用MessageContractAttribute使之成为一个消息契约。从MessageContractAttribute的定义来看,MessageContractAttribute大体上具有以下两种类型的属性成员:
ProtectionLevel和HasProtectionLevel:表示保护级别,在服务契约中已经对保护级别作了简单的介绍,WCF中通过枚举定义消息的保护级别。一般有3种可选的保护级别:None、Sign和EncryptAndSign
IsWrapped、WrapperName、WrapperNamespace:IsWrapped表述的含义是是否为定义的主体成员(一个或者多个)添加一个额外的根节点。WrapperName和WrapperNamespace则表述该根节点的名称和命名空间。IsWrapped、WrapperName、WrapperNamespace的默认是分别为true、类型名称和。
1: [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class, AllowMultiple = false)]
2: public sealed class MessageContractAttribute : Attribute
//其他成员
public bool
HasProtectionLevel { }
public ProtectionLevel
ProtectionLevel { }
public bool
IsWrapped { }
public string
WrapperName { }
public string
WrapperNamespace { }
下面的代码中将Customer类型通过应用MessageContractAttribute使之成为一个消息契约。ID和Name属性通过应用MessageHeaderAttribute定义成消息报头(Header)成员,而Address属性则通过MessageBodyMemberAttribute定义成消息主体(Body)成员。后面的XML体现的是Customer对象在SOAP消息中的表现形式。
1: [MessageContract]
2: public class Customer
[MessageHeader(Name = "CustomerNo", Namespace = "/")]
public Guid ID
[MessageHeader(Name = "CustomerName", Namespace = "/")]
public string Name
[MessageBodyMember(Namespace = "/")]
public string Address
1: &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://tempuri.org/IOrderManager/ProcessOrder&/a:Action&
&h:CustomerName xmlns:h="/"&Foo&/h:CustomerName&
&h:CustomerNo xmlns:h="/"&2f62405b-a472-4d1c-8c03-b888f9bd0df9&/h:CustomerNo&
&/s:Header&
&Customer xmlns="http://tempuri.org/"&
&Address xmlns="/"&#328, Airport Rd, Industrial Park, Suzhou Jiangsu Province&/Address&
&/Customer&
12: &/s:Envelope&
如果我们将IsWrapped的属性设为false,那么套在Address节点外的Customer节点将会从SOAP消息中去除。
1: [MessageContract(IsWrapped = false)]
2: public class Customer
//省略成员
1: &s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope"&
&Address xmlns="/"&#328, Airport Rd, Industrial Park, Suzhou Jiangsu Province&/Address&
6: &/s:Envelope&
我们同样可以自定义这个主体封套(Wrapper)的命名和命名空间。下面我们就通过将MessageContractAttribute的WrapperName和WrapperNamespace属性设为Cust和/。
1: [MessageContract(IsWrapped = true, WrapperName = "Cust", WrapperNamespace = "/")]
2: public class Customer
//省略成员
1: &s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope"&
&Cust xmlns="/"&
&Address&#328, Airport Rd, Industrial Park, Suzhou Jiangsu Province&/Address&
8: &/s:Envelope&
2、MessageHeaderAttribute
MessageHeaderAttribute和MessageBodyMemberAttribute分别用于定义消息报头成员和消息主体成员,它们都有一个共同的基类:。MessageContractMemberAttribute定义了以下属性成员:HasProtectionLevel、ProtectionLevel、Name和Namespace。
1: public abstract class MessageContractMemberAttribute : Attribute
public bool
HasProtectionLevel { }
public ProtectionLevel
ProtectionLevel { }
public string
public string
Namespace { }
通过在属性或者字段成员上应用MessageHeaderAttribute使之成为一个消息报头成员。MessageHeaderAttribute定义了以下3个属性,如果读者对SOAP规范有一定了解的读者,相信对它们不会陌生。
注:在《WCF技术剖析(卷1)》中的第六章有对SOAP 1.2的基本规范有一个大致的介绍,读者也可以直接访问W3C网站下载官方文档。
Actor:表示处理该报头的目标节点(SOAP Node),SOAP1.1中对应的属性(Attribute)为actor,SOAP 1.2中就是我们介绍的role属性
MustUnderstand:表述Actor(SOAP 1.1)或者Role(SOAP 1.2)定义的SOAP节点是否必须理解并处理该节点。对应的SOAP报头属性为mustUnderstand
Relay:对应的SOAP报头属性为relay,表明该报头是否需要传递到下一个SOAP节点
1: [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
2: public class MessageHeaderAttribute : MessageContractMemberAttribute
public string
public bool
MustUnderstand { }
public bool
同样使用上面定义的Customer消息契约,现在我们相应地修改了ID属性上的MessageHeaderAtribute设置:MustUnderstand = true, Relay=true, Actor=http://www.w3.org/ 2003/05/soap-envelope/role/ultimateReceiver。实际上将相应的SOAP报头的目标SOAP节点定义成最终的消息接收者。由于http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver是SOAP 1.2的预定义属性,所以这个消息契约之后在基于SOAP 1.2的消息版本中有效。后面给出的为对应的SOAP消息。
1: [MessageContract(IsWrapped =true, WrapperNamespace="/")]public class Customer
//其他成员
[MessageHeader(Name="CustomerNo", Namespace = "/" ,MustUnderstand = true, Relay=true, Actor="http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver" )]
public Guid ID
1: &s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope"&
&s:Header&
&h:CustomerNo s:role="http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver" s:mustUnderstand="1" s:relay="1" xmlns:h="/"&fd7-4bf5-ae3e-4ba9bfef3d4d&/h:CustomerNo&
&/s:Header&
7: &/s:Envelope&
http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver在SOAP1.1中对应的表示为:"http://schemas.xmlsoap.org/soap/actor/ultimateReceiver(具有不同的命名空间)。如果在SOAP 1.1下,ID成员对应的MessageHeaderAttribute应该做如下的改动。从对应的SOAP消息来看,在SOAP 1.2中的role属性变成了actor属性。
1: [MessageContract(IsWrapped =true, WrapperNamespace="/")]public class Customer
//其他成员
[MessageHeader(Name="CustomerNo", Namespace = "/" ,MustUnderstand = true, Relay=true, Actor="http://schemas.xmlsoap.org/soap/actor/ultimateReceiver" )]
public Guid ID
1: &s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"&
&s:Header&
&h:CustomerNo s:actor="http://schemas.xmlsoap.org/soap/actor/ultimateReceiver" s:mustUnderstand="1" xmlns:h="/"&e48af8-b5e7-cd16be4c75b7&/h:CustomerNo&
&/s:Header&
7: &/s:Envelope&
3、MessageBodyMemberAttribute
MessageBodyMemberAttribute应用于属性或者字段成员,应用了该特性的属性或者字段的内容将会出现在SOAP的主体部分。MessageBodyMemberAttribute的定义显得尤为简单,仅仅具有一个Order对象,用于控制成员在SOAP消息主体中出现的位置。默认的排序规则是基于字母排序。
可能细心的读者会问,为什么MessageHeaderAttribute中没有这样Order属性呢?原因很简单,MessageHeaderAttribute定义的是单个SOAP报头,SOAP消息报头集合中的每个报头元素是次序无关的。而MessageBodyMemberAttribute则是定义SOAP主体的某个元素,主体成员之间的次序也是契约的一个重要组成部分。所以MessageHeaderAttribute不叫MessageHeaderMemberAttribute。
1: [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, Inherited = false)]
2: public class MessageBodyMemberAttribute : MessageContractMemberAttribute
public int Order { }
二、实例演示:基于消息契约的方法调用是如何格式化成消息的?
在WCF体系中,MessageFormatter负责序列化和反序列化任务(在《WCF技术剖析(卷1)》中的第5章对基于MessageFormatter的序列化机制有详细的介绍):ClientMessageFormatter和DispatchMessageFormatter分别在客户端和服务端,根据操作的描述(Operation Description),借助于相应的序列化器(Serializer)实现了方法调用与消息之间的转换。接下来,我将通过一个实实在在的案例程序为大家演示如何通过ClientMessageFormatter将输入参数转换为基于当前服务操作的Message。由于本节的主题是消息契约,所以在这里我们将转换对象限定为消息契约。不过,不论是消息参数还是一般的可序列化对象,其转换过程都是一样的。
步骤一:创建消息契约
本案例模拟一个订单处理的WCF应用,我们首先定义如下一个Order类型。Order是一个消息契约,属性OrderID和Date通过MessageHeaderAttribute定义成消息报头,作为主体的Details的类型OrderDetails被定义成集合数据契约。OrderDetails的元素类型是数据契约OrderDetail,代表订单中每笔产品明细。
1: using S
2: using System.Collections.G
3: using System.Runtime.S
4: using System.ServiceM
5: namespace Artech.TypedMessage
[MessageContract]
public class Order
[MessageHeader(Namespace ="/")]
public Guid OrderID
[MessageHeader(Namespace ="/")]
public DateTime Date
[MessageBodyMember]
public OrderDetails Details
public override string ToString()
return string.Format("Oder ID: {0}\nDate: {1}\nDetail Count: {2}",this.OrderID,this.Date.ToShortDateString(),this.Details.Count);
[CollectionDataContract(ItemName = "Detail",Namespace ="/")]
public class OrderDetails : List&OrderDetail&
[DataContract(Namespace ="/")]
public class OrderDetail
[DataMember]
public Guid ProductID
[DataMember]
public int Quantity
步骤二:创建MessageFormatter
本例的目的在于重现WCF如何通过ClientMessageFormatter实现将输入参数序列化成请求消息,以及通过DispatchMessageFormatter实现将请求消息反序列化成输入参数。根据使用的序列化器的不同,WCF中定义了两种典型的MessageFormatter:一种是基于DataContractSerializer的DataContractSerializerOperationFormatter;另一种则是基于XmlSerializer的XmlSerializerOperationFormatter。由于DataContractSerializerOperationFormatter是默认的MessageFormatter,所以我们这个案例就采用DataContractSerializerOperationFormatter。
我们的任务就是创建这个DataContractSerializerOperationFormatter。由于这是一个定义在System.ServiceModel.Dispatcher命名空间下的内部(internal)类型,所以我们只能通过反射的机制调用构造函数来创建这个对象。DataContractSerializerOperationFormatter定义了唯一的一个构造函数,3个输入参数类型分别为:OperationDescription,DataContractFormatAttribute和DataContractSerializerOperationBehavior。
1: internal class DataContractSerializerOperationFormatter : OperationFormatter
//其他成员
public DataContractSerializerOperationFormatter(OperationDescription description, DataContractFormatAttribute dataContractFormatAttribute, DataContractSerializerOperationBehavior serializerFactory);
为此我们定义下面一个辅助方法CreateMessageFormatter&TFormatter, TContract&。TFormatter代表MessageFormatter的两个接口:IClientMessageFormatter和IDispatchMessageFormatter(DataContractSerializerOperationFormatter同时实现了这两个接口),TContract则是服务契约的类型。参数operationName为当前操作的名称。代码不算复杂,主要的流程如下:通过服务契约类型创建ContractDescription,根据操作名称得到OperationDescription对象。通过反射机制调用DataContractSerializerOperationFormatter的构造函数创建该对象。
1: static TFormatter CreateMessageFormatter&TFormatter, TContract&(string operationName)
ContractDescription contractDesc = ContractDescription.GetContract(typeof(TContract));
var operationDescs = contractDesc.Operations.Where(op =& op.Name == operationName);
if(operationDescs.Count() == 0)
throw new ArgumentException("operationName","Invalid operation name.");
OperationDescription operationDesc = operationDescs.ToArray()[0];
string formatterTypeName = "System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter,System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c";
Type formatterType = Type.GetType(formatterTypeName);
ConstructorInfo constructor = formatterType.GetConstructor(new Type[] { typeof(OperationDescription), typeof(DataContractFormatAttribute), typeof(DataContractSerializerOperationBehavior) });
13: return (TFormatter)constructor.Invoke(new object[] { operationDesc, new DataContractFormatAttribute(), null });
MessageFormatter已经创建出来了,序列化与反序列化的问题就很简单了。为此我定义了以下两个辅助方法:SerializeRequest&TContract&和DeserializeRequest&TContract&,具体实现就是调用创建出来的MessageFormatter的同名方法。
1: static Message SerializeRequest&TContract&(MessageVersion messageVersion, string operationName, params object[] values)
IClientMessageFormatter formatter = CreateMessageFormatter&IClientMessageFormatter, TContract&(operationName);
return formatter.SerializeRequest(messageVersion, values);
7: static void DeserializeRequest&TContract&(Message message, string operationName, object[] parameters)
IDispatchMessageFormatter formatter = CreateMessageFormatter&IDispatchMessageFormatter, TContract&(operationName);
formatter.DeserializeRequest(message, parameters);
步骤三:通过MessageFormmatter实现消息的格式化
现在我们通过一个简单的例子来演示通过上面创建的MessageFormatter实现对消息的格式化。由于MessageFormatter进行序列化和反序列化依赖于操作的描述(消息的结构本来就是由操作决定的),为此我们定义了一个服务契约IOrderManager。操作ProcessOrder将消息契约Order作为唯一的参数。
1: using System.ServiceM
2: namespace Artech.TypedMessage
[ServiceContract]
public interface IOrderManager
[OperationContract]
void ProcessOrder(Order order);
在下面的代码中,先调用SerializeRequest&IOrderManager&方法将Order对象进行序列化并生成Message对象,该过程实际上体现了WCF的客户端框架是如何通过ClientMessageFormatter将操作方法调用连同输入参数转换成请求消息的。随后,调用DeserializeRequest&IOrderManager&方法将Message对象反序列化成Order对象,该过程则代表WCF的服务端框架是如何通过DispatchMessageFormatter将请求消息反序列化成输入参数的。
1: OrderDetail detail1 = new OrderDetail
ProductID = Guid.NewGuid(),
Quantity = 666
7: OrderDetail detail2 = new OrderDetail
ProductID = Guid.NewGuid(),
Quantity = 999
13: Order order = new Order
OrderID = Guid.NewGuid(),
Date = DateTime.Today,
Details = new OrderDetails { detail1, detail2 }
19: //模拟WCF客户端的序列化
20: Message message = SerializeRequest&IOrderManager&(MessageVersion.Default, "ProcessOrder", order);
21: MessageBuffer buffer = message.CreateBufferedCopy(int.MaxValue);
22: WriteMessage(buffer.CreateMessage(), "message.xml");
24: //模拟WCF服务端的反序列化
25: object[] DeserializedOrder = new object[]{ null };
26: DeserializeRequest&IOrderManager&(buffer.CreateMessage(), "ProcessOrder", DeserializedOrder);
27: Console.WriteLine(DeserializedOrder[0]);
下面的XML表示调用SerializeRequest&IOrderManager&生成的SOAP消息。程序最终的输出结果也表明了反序列化的成功执行。
1: &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://tempuri.org/IOrderManager/ProcessOrder&/a:Action&
&h:Date xmlns:h="/"&T00:00:00+08:00&/h:Date&
&h:OrderID xmlns:h="/"&cd94a6f0-7e21-4ace-83f7-2ddf061cfbbe&/h:OrderID&
&/s:Header&
&Order xmlns="http://tempuri.org/"&
&Details xmlns:d4p1="/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"&
&d4p1:Detail&
&d4p1:ProductID&bc2a186d-569a--c0&/d4p1:ProductID&
&d4p1:Quantity&666&/d4p1:Quantity&
&/d4p1:Detail&
&d4p1:Detail&
&d4p1:ProductID&b2--da6d040587fc&/d4p1:ProductID&
&d4p1:Quantity&999&/d4p1:Quantity&
&/d4p1:Detail&
&/Details&
21: &/s:Envelope&
1: Oder ID: cd94a6f0-7e21-4ace-83f7-2ddf061cfbbe
2: Date: 12/21/2008
3: Detail Count: 2
作者:出处: 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
阅读(...) 评论()请问 WCF DataContract 类,其 method 被客户端调用问题
[问题点数:100分,结帖人WizardWu]
请问 WCF DataContract 类,其 method 被客户端调用问题
[问题点数:100分,结帖人WizardWu]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
相关帖子推荐:
本帖子已过去太久远了,不再提供回复功能。处理WCF异常的方式 - 每天积累 - ITeye技术网站
博客分类:
任何程序都离不开对异常的处理,良好的异常处理方式可加快寻找出异常的根源,同时也需要避免暴露敏感信息到异常中。WCF这种典型的服务端和客户端交互的程序,服务端的异常更需要适当的处理。下面以一个简单的服务为例,说明WCF中处理异常的方式。
WCF服务定义如下,很明显方法Divide在divisor为0的时候将会抛出异常
public class CalculateService : ICalculateService
public int Divide(int dividend, int divisor)
return dividend /
public int Add(int a, int b)
return a +
客户端调用如下:
using (var client = new CalculateServiceClient())
Console.WriteLine(client.Divide(20, 0));
catch (FaultException ex)
Console.WriteLine(ex.Reason);
首先需要知道的是,WCF的异常信息默认是以FaultException的形式返回到客户端,FaultException的关键属性 Reason是对客户端反馈的最重要信息之一。以上客户端代码调用之后,默认的FaultException返回的Message信息如下:
由于内部错误,服务器无法处理该请求。有关该错误的详细信息,请 打开服务器上的 IncludeExceptionDetailInFaults (从 ServiceBehaviorAttribute 或从 &serviceDebug& 配置行为)以便将异常信息发送回客户端,或在打开每个 Microsoft .NET Framework 3.0 SDK 文档的跟踪的同时检查服务器跟踪日志。
根据异常的提示,意思说如果要在客户端看到详细的Exception信息,那么请将ServiceBehavior对应的IncludeExceptionDetailInFaults属性设置为True,通常在配置中表现为如下设置:
1 &serviceBehaviors&2
&behavior&3
&serviceMetadata httpGetEnabled="True" httpGetUrl="http://localhost:8733/CalculateService/"/&4
&serviceDebug includeExceptionDetailInFaults="True" /&5
&/behavior&6
&/serviceBehaviors&
通过以上设置之后,客户端输出的内容为“尝试除以零”,这个提示信息跟原始的异常信息是一致,即返回的FaultException中的 Reason包含原始异常的Message的值,但是这样处理之后服务端所报出的异常信息直接传到了客户端,比如一些保密信息也可能输出到了客户端,因此 对于异常信息必须进行一个封装。最直接的形式莫过于在服务端就把异常给捕获了,并重新throw一个FaultException
服务端的代码改进如下,经过以下改进,那么客户端得到的信息仅仅是"操作失败",同时服务端也记录了异常信息(这时IncludeExceptionDetailInFaults是设置为False的)。
return dividend /4
catch (Exception ex)6
Console.WriteLine(ex.Message);8
throw new FaultException("操作失败");9
当然这是FaultException的默认用法,FaultException还支持强类型的异常错误信息,返回更加丰富和精确的错误提示。假设 定义如下通用的一个FaultContract类型,将出错时的用户名和线程名字记录到异常信息中,因为异常信息也是通过SOAP格式传输的,因此跟定义 其他DataContract的方式一样。
CommonFaultContract
[DataContract]2
public class CommonFaultContract3
[DataMember]5
public string UserName { get; set; }6
[DataMember]7
public string
ThreadName { get; set; }8
那么服务方法的接口需要增加如下标记,如果不这样标记,那么客户端得到的异常类型依然是FaultException,而不是强类型的异常信息。
[FaultContract(typeof(CommonFaultContract))] int Divide(int dividend, int divisor)
实现方法中抛出异常的部分代码改成如下:
1 catch (Exception ex)2
Console.WriteLine(ex.Message);4
throw new FaultException&CommonFaultContract&(new CommonFaultContract 5
UserName = Environment.UserName,7
ThreadName = System.Threading.Thread.CurrentThread.Name8
}, "操作失败");9
这时候重新生成客户端的代理类,然后更新客户端的代码如下,红色部分即获取强类型的异常错误信息。
Console.WriteLine(client.Divide(20, 0)); 4
catch (FaultException&CommonFaultContract& ex) 6
Console.WriteLine(ex.Detail.ThreadName); 8
Console.WriteLine(ex.Detail.UserName); 9
Console.WriteLine(ex.Reason);10
当然在具体应用中还需要根据需求,返回不同的信息,构建不同的FaultContract。
  以上服务端捕获的异常方法,适用于方法比较少的情况,如果有十多个方法,一个个去写try catch然后做标记等,那么工作量会很大,而且代码也不利于重用。尝试寻找像MVC Controller那样的统一处理Exception的方式,将异常处理都放在基类中,那么只要继承与这个基类的方法都不需要去写try catch去捕获异常。但WCF中似乎没有这样的机制,放弃了这种做法。
  最近在研究Enterprise Lib中对WCF的支持时,发现Exception Block中还特地有针对WCF程序异常处理的解决方案,而且满足以上说道的需求,即可记录异常,又可对异常信息进行封装。更重要的时,自动处理运行时的 异常信息,不需要挨个方法的去写Try catch。秉承企业库的优秀传统,大部分工作还是通过配置就可以完成了,非常好的解决方案。下面介绍具体的使用步骤。
引用以下dll
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll
Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.dll
Microsoft.mon.dll
Microsoft.Practices.ObjectBuilder2.dll
在具体的实现类中,增加如下属性标记,其中WcfException为企业库中Exception Block中的一个异常处理策略,具体如何配置异常处理策略,请参考企业库的帮助文档。
[ExceptionShielding("WcfException")]public class CalculateService : ICalculateService
那么只要增加了[ExceptionShielding("WcfException")]这个属性标记之后,所有运行时的异常都将交给策略名为WcfException的异常处理block来处理,在这里就可以执行一些异常记录以及异常封装的操作。
将异常信息封装为FaultException,这个动作也是通过配置来完成。在Exception节点中添加一个Fault Contract Exception Handler。
Fault Contract Exception Handler需要设置以下两个属性值
exceptionMessage:所有异常封装后的错误信息
faultContractType:即返回异常的faltContract类型,这个类型必须指定一个,哪怕方法中没有用到也要,如果方法中有用 到,那么客户端那边就能得到强类型FaultException,否则就是普通的FaultException。这里指定为之前定义的CommonFaultContract。
对于faultContract类型的值,还可以通过PropertyMappings来自定义需要从原始异常信息中映射到faultContract的属性中,这个属性可选。
  经过以上步骤配置之后,服务端的程序就具备了自动处理异常的功能。客户端还是跟往常那样调用,不过具体是用FaultException捕获异 常还是FaultException&T&去捕获异常,还得根据定义方法中是否标记了FaultContract。之后若定义了其他服务接 口,同样也仅仅需要在实现类上加上[ExceptionShielding("WcfException")]标记即可。
浏览: 387235 次
来自: 天津
Flex4开发视频教程(27集)下载http://bbs.it ...
Jquery+asp.net 后台数据传到前台js进行解析的办 ...
谢谢谢谢!!
vigiles 写道请问楼主:[Fault] exceptio ...
请问楼主:[Fault] exception, informa ...

我要回帖

更多关于 datacontract 的文章

 

随机推荐