Mongodb的性质优化难题

摘要

数据库品质对软件全体品质兼备至关首要的震慑,对于Mongodb数据库常用的性质优化措施首要有:

  1. 范式化与反范式化;
  2. 填充因子的运用;
  3. 目录的选拔;

通过WCF基本的足够处理格局[上篇]
大家了解了:在默许的情状下,服务端在进行有个别服务操作时抛出的12分(在此地指非FaultException分外),其相关的错误新闻仅仅限于服务端可知,并不会被WCF传递到客户端;要是将翻开了IncludeExceptionDetailInFaults的ServiceDebug服务行为经过注脚(通过在服务类型上使用ServiceBehaviorAttrite性情)大概布置的不二法门使用到相应的劳动上,相当相关的保有细节新闻将会纹丝不动地向客户端传送。

一. 范式化与反范式化

范式是为了破除重复数据回落冗余数据,从而让数据库内的数据更好的团组织,让磁盘空间得到更管用应用的一种口径标准,满意高等级的范式的先决条件是知足低等级范式。在数据库设计阶段,鲜明集合的用处是对mongodb数据库品质调优卓殊首要的一步。依据集合中数据最常用的操作,对于频仍更新和反复查询的集结,大家最亟需关心的首要性是她们的范式化程度。

起名,那两种情势显示了二种极端的充足传播(Exception
Propagation)机制,对于基于服务操作实施进度中抛出的那多少个的不当细节,要么完全对客户端屏蔽,要么整体爆出于客户端。在真的通过WCF来框架结构我们的分布式系统中,大家往往需求一种折中的很是传播机制:自定义服务端卓殊音讯。这样既能够让客户端获得三个便于驾驭的错误消息,又在必然水平上制止了一部分机智消息的透漏。

1.1 范式化

1.1.1 范式化的独到之处:

  1. 范式化的数据库更新起来尤其速;
  2. 范式化之后,唯有很少的重新数据,只须求修改更少的多寡;
  3. 范式化的表更小,能够在内部存款和储蓄器中推行;
  4. 很少的冗余数据,在询问的时候须要更少的distinct可能group by语句。

1.1.2 范式化的缺点:

  1. 范式化的表,在询问的时候日常必要广大的涉及,因为单独一个表内不设有冗余和重新数据。那致使,稍微复杂一些的查询语句在查询范式的schema上都只怕需求较多次的涉嫌。那会增多让查询的代价,也恐怕使有些索引策略无效。因为范式化将列存放在不相同的表中,而那么些列在三个表中本能够属于同1个索引。

1.1.3 范式化设计的例子:
以存款和储蓄一篇图书及其小编为例,作者的音讯包含小编的真名,年龄,国籍。使用范式化的布署性如下:

{
    "_id" : ObjectId("5124b5d86041c7dca81917"),
    "title" : "如何使用MongoDB", 
    "author" : [ 
             ObjectId("144b5d83041c7dca84416"),
             ObjectId("144b5d83041c7dca84418"),
             ObjectId("144b5d83041c7dca84420"),
    ]
}

将小编(comment)
的id数组作为2个字段添加到了书籍中去。那样的规划艺术是在非关系型数据库中常用的。在MongoDB中大家将与主键没有直接关乎的撰稿人详细音信单独提取到另3个成团,用存款和储蓄主键的格局开始展览关联合检查询。当我们要询问小说和小编时索要先查询到所需的作品,再从小说小编中获得小编id,最终收获的完好的稿子及其作者详细音信。在那种情景下询问质量鲜明是无法的,因为必要开始展览较多的关系查询。但当某位小编的音讯供给修改时,范式化的爱惜优势就呈现出来了,大家无需考虑此小编提到的书本,直接开始展览改动此作者的字段即可。

壹 、 通过FaultException直接钦赐错误音讯

1.2. 反范式化

1.2.1 反范式化的亮点:

  1. 可防止止关联,因为拥有的多寡大概都得以在一张表上突显;
  2. 能够安排使得的目录;

1.2.2 反范式化的弱点:

  1. 报表内的冗余较多,删除数据时候会招致表某些有用的新闻丢失。

1.2.3 反范式化设计的事例:
以存款和储蓄一篇图书及其小编为例,我的音讯包含作者的姓名,年龄,国籍。使用反范式化的安插性如下:

{
      "_id" : ObjectId("5124b5d86041c7dca81917"),
      "title" : "如何使用MongoDB",
      "author" : [
               {
                        "name" : "丁磊"
                        "age" : 40,
                        "nationality" : "china",
               },
               {
                        "name" : "马云"
                        "age" : 49,
                        "nationality" : "china",
               },
               {
                        "name" : "张召忠"
                        "age" : 59,
                        "nationality" : "china",
               },
     ]
}     

在这一个示例中大家将作者的字段完全置于到了书本中去,在询问的时候一贯询问图书即可获取所对应小编的整个音信,但因1个小编大概有多本文章,当修改某位我的音讯时,大家须求遍历全部书籍以找到该小编,将其修改。

对此推行服务操作中抛出的要命,借使服务的定义者仅仅希望劳动的调用者获得一段自定义的错误音信文本(字符串),咱们要做的实在相当粗略:在劳务操作中央直机关接抛出二个FaultException极度,该特别对象通过以字符串格局反映的自定义错误音信创立。下边包车型大巴代码中,CalculaorService的Divide方式在内定的时候对第一参数举办了表达,假使为零则创立1个FaultException,并钦命错误音讯(“被除数y不能够为零!”)。

1.3 范式化与反范式化混用

为了兼顾范式化与反范式化的得失,日常较常利用范式化与反范式化混合使用的法门,混合范式化与反范式化的安顿如下:

{
      "_id" : ObjectId("5124b5d86041c7dca81917"),
      "title" : "如何使用MongoDB",
      "author" : [ 
              {
                        "_id" : ObjectId("144b5d83041c7dca84416"),
                        "name" : "丁磊"
               },
               {
                        "_id" : ObjectId("144b5d83041c7dca84418"),
                        "name" : "马云"
               },
               {
                        "_id" : ObjectId("144b5d83041c7dca84420"),
                        "name" : "张召忠"
               },
     ]
} 

那种办法是一种周旋折中的方式,既保障了询问成效,也准保的立异频率。但如此的法子一目明白要比前二种较难以通晓,难点在于要求与实际工作举办组合来寻觅合适的提取字段。

   1: using System.ServiceModel;

   2: using Artech.WcfServices.Contracts;

   3: namespace Artech.WcfServices.Services

   4: {

   5:     [ServiceBehavior(IncludeExceptionDetailInFaults = true)]

   6:     public class CalculatorService : ICalculator

   7:     {

   8:         public int Divide(int x, int y)

   9:         {

  10:             if (0 == y)

  11:             {

  12:                 throw new FaultException("被除数y不能为零!");

  13:             }

  14:             return x / y;

  15:         }

  16:     }

  17: }

1.4 总结

  1. 范式化的更新频率是最高的,但询问功能是最低的;
  2. 反范式化的询问效能最高,但立异频率最低;
  3. 在事实上的干活中大家供给依照本人其实的须求来陈设表中的字段,以取得最高的成效。

客户端在调用该服务操作的时候,若是传入零当作被除数,将会直接破获服务端定义的抛出的这一个格外(实际上,那里面经验了老大对象的体系化、信息交流以及尤其对象的反类别化等一种类的操作)。客户端具体的格外捕获情状如下边包车型地铁次序显示:

二. 填充因子的采取

填充因子(padding
factor)是MongoDB为文书档案的扩充而留给的增长空间,因为MongoDB的文书档案是以顺序表的法子存款和储蓄的,每一种文档之间会很是紧凑。
填充因子的精通之所以首要,是因为文书档案的位移十分消耗品质,频仍的移位会大大增添系统的负责,在骨子里支付中最有恐怕会让文书档案体积变大的元素是数组,所以假若我们的文书档案会频仍修改并附加空间的话,则必定要丰硕考虑填充因子。

   1: using System;

   2: using System.ServiceModel;

   3: using Artech.WcfServices.Contracts;

   4: namespace Artech.WcfServices.Clients

   5: {

   6:     class Program

   7:     {

   8:         static void Main(string[] args)

   9:         {

  10:             using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>(

  11:                "calculatorservice"))

  12:             {

  13:                 ICalculator calculator = channelFactory.CreateChannel();

  14:                 using (calculator as IDisposable)

  15:                 {

  16:                     try

  17:                     {

  18:                         int result = calculator.Divide(1, 0);

  19:                     }

  20:                     catch (FaultException ex)

  21:                     {

  22:                         Console.WriteLine(ex.Message);

  23:                         (calculator as ICommunicationObject).Abort();

  24:                     }

  25:                 }

  26:             }

  27:         }

  28:     }

  29: }

2.1 常用的三种艺术

2.1.1 扩大开首分配空间
在聚集的习性中蕴藏二个 usePowerOf2Sizes
属性,当那一个选项为true时,系统会将后续插入的文书档案,早先空间都分配为2的N次方。
这种分配机制适用于四个数据会频仍变动的聚集使用,他会给每种文书档案留有更大的空中,但由此空间的分红不会像原来那么高速,假诺您的聚众在更新时不会反复的面世活动现象,那种分配方式会造成写入速度相对变慢。

2.1.2 利用多少强行将初叶分配空间扩张

db.book.insert({
   "name" : "MongoDB",
   "publishing" : "清华大学出版社",
   "author" : "john",
   "tags" : [],
   "stuff" : "ggggggggggggggggggggggggggggggggggggg
              ggggggggggggggggggggggggggggggggggggg
              ggggggggggggggggggggggggggggggggggggg"
})

那般看起来或者不太优雅,但有时候却很实用!当大家对那个文档举办增加式修改时,只要将stuff字段删掉即可。当然,这一个stuff字段随便你怎么起名,包蕴内部的填充字符当然也是足以任意添加的。

出口结果:

三. 索引的选用

目录对于贰个数据库的震慑相信咱们一定通晓,假设贰个查询命令进入到数据库中后,查询优化器没有找到确切的目录,那么数据库会进行全集合扫描(在奇骏DBMS中也叫全表扫描),全集合查询对于质量的影响是惨不忍睹的。没有索引的查询就犹如在词典那不用规律的雅量词汇中收获有个别你想要的词汇,但这几个词典是没有目录的,只可以通过逐页来搜寻。那样的物色或许会让你消耗多少个钟头的时日,但万一须要您询问词汇的频率仿佛用户访问的频率一样的话。。。嘿嘿,笔者相信您肯定会惊呼“老子不干了!”。显明总结机不会这么喊,它向来是叁个起早摸黑的职工,不论多么苛刻的伸手他都会完毕。所以请通过索引善待你的计算机。但接纳索引有两点必要小心:1.
索引越少越好;2. 索引颗粒越少越好。

被除数y不能够为零!

3.1 索引越少越好

目录能够相当大地提升查询质量,那么索引是否愈多越好?答案是还是不是定的,并且索引并非越来越多越好,而是越少越好。每当你建立2个索引时,系统会为您添加三个索引表,用于索引钦定的列,不过当你对已创建目录的列实行插队或改动时,数据库则必要对本来的索引表实行再次排序,重新排序的长河丰盛消耗质量,但应对少量的目录压力并不是不小,但借使索引的数据较多的话对于品质的震慑由此可见。所以在创制索引时必要谨慎建立目录,要把每一种索引的意义都要发布到极致,也正是说在能够知足索引须要的情事下,索引的数额越少越好。

即使在不少景观下,在服务端钦命服务操作的经过中一贯抛出含有自定义错误消息的FaultException非凡,就能过客户端感知到境遇的切实错误并开始展览供给的排错和纠错。不过,大家愈来愈多地,照旧援救于直接定义二个档次来描述很是新闻。我个人倾向于那样一类的品种为不当明细类型(Fault
Detail
Type)。服务端根据现实的老大现象创造相应的不当类型对象,并基于该指标咱们地点提到的System.ServiceModel.FaultException<TDetail>很是,个中泛型类型参数为异常的细节类型。在这些历程中,还提到到叁个至关心爱惜要的定义:错误契约(Fault
Contract),接下去,我们就来介绍一下FaultException<TDetail>和不当契约。

3.1 索引颗粒越少越好

如何叫颗粒越小越好?在索引列中各类数据的重复数量称为颗粒,也叫作索引的基数。假诺数量的微粒过大,索引就不可能发挥该有的性质。例如,大家全体贰个”age”列索引,如若在”age”列中,20岁占了4/8,假诺前些天要询问2个20岁,名叫”汤姆”的人,大家则须求在表的四分之二的多寡中询问,索引的效应大大下降。所以,大家在建立目录时要尽量将数据颗粒小的列放在目录左侧,以保障索引发挥最大的法力。

贰 、 通过FaultException<TDetail>采取自定义类型封装错误

四. 尾声

本文主要参考了以下两篇博文:

  1. http://www.cnblogs.com/mokafamily/p/4102829.html
  2. http://blog.csdn.net/puqutogether/article/details/45650963

鉴于用于封装错误新闻的百般细节类型的靶子最后要求通过音信沟通的格局从服务端传播到客户端,所以该对象必须是三个可类别化的目的。WCF通过二种典型体系化器达成对数据对象的体系化和反系列化,当中一个是观念的System.Xml.Serialization.XmlSerializer,该系列换器被ASP.NET
Web服务用于对象和XML之间的体系化和反类别化;另二个则是System.Runtime.Serialization.DataContractSerializer,用于基于数据契约对象的种类化和反连串化,后者是WCF暗中认可采纳的连串化器。所以,可种类化的错误明细类型一般是3个数量契约,可能是一个使用了System.SerializableAttribute个性的体系。关于种类化,和与此相关的数码契约、数据契约连串化器等,在《WCF技术分析(卷1)》的第陆章有尖锐、周密的牵线。

大家照旧用大家地点提到的推测服务来比喻,今后大家供给定义2个独门的种类来讲述基于CalculatorService的格外,我们简直将该品种起名为CalculationError。大家将CalculationError定义成2个选拔了System.Runtime.Serialization.DataContractAttribute特点的数码契约,简单起见,大家唯有定义了五个数据成员(应用了System.Runtime.Serialization.DataMemberAttribute特色):Operation代表造成非常相应的运算操作(我们假如Calculator瑟维斯具有一类别运算操作,固然大家的事例中唯有给出为一二个除法运算操作:Divide),而Message表述具体的荒谬新闻。CalculationError的定义在被客户端(Client项目)和劳务(Services项目)引用的契约(Contracts项目)中,具体定义如下:

   1: using System;

   2: using System.Runtime.Serialization;

   3: namespace Artech.WcfServices.Contracts

   4: {

   5:     [DataContractAttribute(Namespace="http://www.artech.com/")]

   6:     public class CalculationError

   7:     {

   8:         public CalculationError(string operation,string message)

   9:         {

  10:             if (string.IsNullOrEmpty(operation))

  11:             {

  12:                 throw new ArgumentNullException("operation");

  13:             }

  14:             if (string.IsNullOrEmpty(message))

  15:             {

  16:                 throw new ArgumentNullException("message");

  17:             }

  18:             this.Operation = operation;

  19:             this.Message = message;

  20:         }

  21:         [DataMember]

  22:         public string Operation

  23:         { get; set; }

  24:         [DataMember]

  25:         public string Message

  26:         { get; set; }

  27:     }

  28: }

照理说,我们早就正鲜明义了错误明细类型CalculationError,在Calculator瑟维斯的Divide操作中就能够一贯抛出一个Fault<CalculationError>,并将三个创设三个CalculationError对象作为该尤其对象的精心(通过Detail属性表示),具体的代码如下所示:

   1: using System.ServiceModel;

   2: using Artech.WcfServices.Contracts;

   3: namespace Artech.WcfServices.Services

   4: {

   5:     public class CalculatorService : ICalculator

   6:     {

   7:         public int Divide(int x, int y)

   8:         {

   9:             if (0 == y)

  10:             {

  11:                 var error = new CalculationError("Divide", "被除数y不能为零!");

  12:                 throw new FaultException<CalculationError>(error,error.Message);

  13:             }

  14:             return x / y;

  15:         }

  16:     }

  17: }

客户端服务调用相关的充足处理也作如下相应的修改:

   1: using System;

   2: using System.ServiceModel;

   3: using Artech.WcfServices.Contracts;

   4: namespace Artech.WcfServices.Clients

   5: {

   6:     class Program

   7:     {

   8:         static void Main(string[] args)

   9:         {

  10:             using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>(

  11:                "calculatorservice"))

  12:             {

  13:                 ICalculator calculator = channelFactory.CreateChannel();

  14:                 using (calculator as IDisposable)

  15:                 {

  16:                     try

  17:                     {

  18:                         int result = calculator.Divide(1, 0);

  19:                     }

  20:                     catch (FaultException<CalculationError> ex)

  21:                     {

  22:                         Console.WriteLine("运算错误");

  23:                         Console.WriteLine("运算操作:{0}",ex.Detail.Operation);

  24:                         Console.WriteLine("错误消息:{0}",ex.Detail.Message);

  25:                         (calculator as ICommunicationObject).Abort();

  26:                     }

  27:                 }

  28:             }

  29:         }

  30:     }

  31: }

但是大家的客户端程序并不能够依照大家达成预期的那样符合规律运作,而会抛出如图1所示的未被拍卖的FaultException格外,而大家准备捕获的至极类型为FaultException<CalculationError>。

起名 1

图1 客户端不能符合规律捕获FaultException<CalculationError>相当

叁 、错误契约(Fault Contract)

要回应下边出错的案由,就要求谈到WCF也许SOA贰个平昔的特点:服务的提供者和买主之间利用基于“契约(Contract)”的交互格局。差别于面向服务,在面向组件设计中,组件之间的互动实际上是依照项指标,交互双方须要共享相同档次集(接口、抽象类可能具体类等)。在《WCF技术分析(卷1)》中,我们曾多次对契约进行过深远的探赜索隐。从抽象层面上讲,契约时相互双方依旧多方就某一难题实现的一种共同的认识,使保障符合规律交互钦赐的一种类的行业内部。

从实质上讲,服务契约(Service Contract)中的每1个操作契约(Operation
Contract),定义了WCF为兑现该服务操作的调用选择的新闻沟通形式(MEP:Message
Exchange
Pattern),并且结合基于参数、再次回到值类型的数据契约、音讯契约定义了请求消息和苏醒消息的结构(Schema)。数据契约建立了对同样数量的三种不一样表现方式(托管对象和XML)之间的双向适配,以利于承载相同新闻的数额在三种分裂形态之间的更换,即类别换和反体系化。而音讯契约在概念了托管对象的顺序成员与相应的消息成分之间的合营关系。借助于消息契约,在对1个托管对象举办系列化并生成音讯的时候,能够有效地决定某三个多少成员(属性也许字段)被系列化成的XML应该放权新闻报头(Header)依旧新闻主体(Body)。

由此看来,上述的那么些契约基本上都是围绕着3个正规服务调用下的新闻调换:服务的顾客通过向劳动的提供者发送请求信息,服务的提供者在收受到该请求后,激活服务实例并调用相应的劳务操作,最后将回到的结果以复苏音信的情势赶回给服务的顾客(对于One-way,则不必要音讯的还原)。不过,假使服务操作不能够正确地实行,服务端将会因而一种独特的音信将错误音讯再次来到给客户端,这种新闻被称呼错误信息(Fault
Message)。对于错误音讯,同样需求相应的契约来定义其协会,大家把这种契约称为错误契约(Fault
Contract)。

WCF通过System.ServiceModel.FaultContractAttribute特性定义,由于错误契约是基于服务操作级别的,所以该本性直接使用于劳动契约接口或许类的操作契约方法成员上。上边包车型大巴代码片断体现了FaultContractAttribute的定义:

   1: [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]

   2: public sealed class FaultContractAttribute : Attribute

   3: {    

   4:     public FaultContractAttribute(Type detailType);

   5:     public string Action { get; set; }

   6:     public Type DetailType { get; }

   7:     public bool HasProtectionLevel { get; }

   8:     public string Name { get; set; }

   9:     public string Namespace { get; set; }

  10:     public ProtectionLevel ProtectionLevel { get; set; }

  11: }

FaultContractAttribute的五个属性分别装有如下的含义:

  • Action:和一般的SOAP音讯一点差别也没有于,对于Fault
    SOAP,WS-Address报头Action是必须的,该属性控制Action报头的值。要是Action属性没有在利用FaultContractAttribute时显式钦点,那么它将依据上面包车型客车平整进行点名:{服务契约命名空间}/{服务契约名称}/{操作契约名称}{明细类型名称}Fault;
  • DetailType:也正是地点所介绍的用来封装错误音信的一无所长明细类型,比如大家前面定义的CalculationError;
  • Name和Namespace:在终极的Fault
    SOAP中,错误明细对象被种类化成的XML将会被置于Fault
    SOAP的主体部分,而那五个属性则用来控制那段XML片断对应的称号和命名空间;假若那三个性情并未作显式设置,WCF将会利用DetailType对应的数目契约名称和命名空间;
  • HasProtectionLevel和ProtectionLevel:那三个属性涉及到爱护级别,属于安全(Security)的标题,在此地就不多作介绍了。

上边包车型大巴代码中,大家经过FaultContractAttribute将大家定义错误明细类型CalculationError应用到Divide操作之上,那样的话,我们的例子就能够健康运作了。

   1: using System.ServiceModel;

   2: namespace Artech.WcfServices.Contracts

   3: {

   4:     [ServiceContract(Namespace = "http://www.artech.com/")]

   5:     public interface ICalculator

   6:     {

   7:         [OperationContract]

   8:         [FaultContract(typeof(CalculationError))]

   9:         int Divide(int x, int y);

  10:     }   

  11: }

根据大家在地方提到的有关Action、Name和Namespace的暗中认可设定,上面这段代码和底下的代码是一点一滴等同的。

   1: using System.ServiceModel;

   2: namespace Artech.WcfServices.Contracts

   3: {

   4:     [ServiceContract(Name="ICalculator",Namespace = "http://www.artech.com/")]

   5:     public interface ICalculator

   6:     {

   7:         [OperationContract(Name="Divide")]

   8:         [FaultContract(typeof(CalculationError), 

   9:             Action = "http://www.artech.com/ICalculator/DivideCalculationErrorFault",

  10:             Name = "CalculationError", Namespace = "http://www.artech.com/")]

  11:         int Divide(int x, int y);

  12:     }  

  13: }

对于咱们眼下的例子,当客户端调用CalculatorService的Divide操作实践除法预算,并传播零当做被除数,服务端将会抛出FaultException<CalculationError>很是。WCF服务端框架将会发出三个Fault
Message,并将系列化后的CalculationError对象作为不当明细放置到Fault
Message的主心骨部分。若是选用的新闻版本是Soap12Addressing10,即SOAP
1.2和WS-Addressing 1.0,最后生成的Fault Message将会如上面包车型大巴XML片断所示:

   1: <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">

   2:   <s:Header>

   3:     <a:Action s:mustUnderstand="1">http://www.artech.com/ICalculator/DivideCalculationErrorFault</a:Action>    <a:RelatesTo>urn:uuid:3498ba2d-edd0-4d3b-ba4a-9b35327b5fa3</a:RelatesTo>

   4:   </s:Header>

   5:   <s:Body>

   6:     <s:Fault>

   7:       <s:Code>

   8:         <s:Value>s:Sender</s:Value>

   9:       </s:Code>

  10:       <s:Reason>

  11:         <s:Text xml:lang="zh-CN">被除数y不能为零!</s:Text>

  12:       </s:Reason>

  13:       <s:Detail>

  14:         <CalculationError xmlns="http://www.artech.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">

  15:           <Message>被除数y不能为零!</Message>

  16:           <Operation>Divide</Operation>

  17:         </CalculationError>

  18:       </s:Detail>

  19:     </s:Fault>

  20:   </s:Body>

  21: </s:Envelope>

错误契约作为劳动描述的一局地,会到场到描述服务的元数据(Metadata)中。当服务元数据通过WSDL的样式被公布的时候,作为对操作的描述的百无一用契约浮未来WSDL的<wsdl:portType>/<wsdl:operation>/<wsdl:fault>节点。上边一段XML代表CalculatorService的WDSL:

   1: <?xml version="1.0" encoding="utf-8"?>

   2: <wsdl:definitions name="CalculatorService" targetNamespace="http://www.artech.com/" >

   3:   <wsdl:import namespace="http://tempuri.org/" location="http://127.0.0.1:3721/calculatorservice/mex?wsdl=wsdl0"/>

   4:   <wsdl:types>

   5:     <xs:schema elementFormDefault="qualified" targetNamespace="http://www.artech.com/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.artech.com/">

   6:       <xs:element name="Divide">

   7:         <xs:complexType>

   8:           <xs:sequence>

   9:             <xs:element minOccurs="0" name="x" type="xs:int"/>

  10:             <xs:element minOccurs="0" name="y" type="xs:int"/>

  11:           </xs:sequence>

  12:         </xs:complexType>

  13:       </xs:element>

  14:       <xs:element name="DivideResponse">

  15:         <xs:complexType>

  16:           <xs:sequence>

  17:             <xs:element minOccurs="0" name="DivideResult" type="xs:int"/>

  18:           </xs:sequence>

  19:         </xs:complexType>

  20:       </xs:element>

  21:       <xs:complexType name="CalculationError">

  22:         <xs:sequence>

  23:           <xs:element minOccurs="0" name="Message" nillable="true" type="xs:string"/>

  24:           <xs:element minOccurs="0" name="Operation" nillable="true" type="xs:string"/>

  25:         </xs:sequence>

  26:       </xs:complexType>

  27:       <xs:element name="CalculationError" nillable="true" type="tns:CalculationError"/>

  28:     </xs:schema>

  29:   </wsdl:types>

  30:   <wsdl:message name="ICalculator_Divide_InputMessage">

  31:     <wsdl:part name="parameters" element="tns:Divide"/>

  32:   </wsdl:message>

  33:   <wsdl:message name="ICalculator_Divide_OutputMessage">

  34:     <wsdl:part name="parameters" element="tns:DivideResponse"/>

  35:   </wsdl:message>

  36:   <wsdl:message name="ICalculator_Divide_CalculationErrorFault_FaultMessage">

  37:     <wsdl:part name="detail" element="tns:CalculationError"/>

  38:   </wsdl:message>

  39:   <wsdl:portType name="ICalculator">

  40:     <wsdl:operation name="Divide">

  41:       <wsdl:input wsaw:Action="http://www.artech.com/ICalculator/Divide" message="tns:ICalculator_Divide_InputMessage"/>

  42:       <wsdl:output wsaw:Action="http://www.artech.com/ICalculator/DivideResponse" message="tns:ICalculator_Divide_OutputMessage"/>

  43:       <wsdl:fault wsaw:Action="http://www.artech.com/ICalculator/DivideCalculationErrorFault" name="CalculationErrorFault" message="tns:ICalculator_Divide_CalculationErrorFault_FaultMessage"/>

  44:     </wsdl:operation>

  45:   </wsdl:portType>

  46:   <wsdl:service name="CalculatorService">

  47:     <wsdl:port name="CustomBinding_ICalculator" binding="i0:CustomBinding_ICalculator">

  48:       <soap12:address location="http://127.0.0.1:3721/calculatorservice"/>

  49:       <wsa10:EndpointReference>        <wsa10:Address>http://127.0.0.1:3721/calculatorservice</wsa10:Address>

  50:       </wsa10:EndpointReference>

  51:     </wsdl:port>

  52:   </wsdl:service>

  53: </wsdl:definitions>

对此错误契约的行使,还有有些亟需专门表明:不仅仅是将自定义的谬误明细类型(比如CalculationError)应用到相应的操作契约上,你必要显失地应用FaultContractAttribute个性将其选取到服务契约接口只怕类中相应的操作方法下边,对于部分基元类型,比如Int32,String等,你也亟需如此。也便是说,同样对于大家的计量服务的事例,假若服务端试图透过抛出3个FaultException<string>来提供错误(如上边包车型客车代码所示),客户端最终捕获到的不过是三个FaultException非凡,而非FaultException<string>分外。

   1: using System.ServiceModel;

   2: using Artech.WcfServices.Contracts;

   3: namespace Artech.WcfServices.Services

   4: {

   5:     public class CalculatorService : ICalculator

   6:     {

   7:         public int Divide(int x, int y)

   8:         {

   9:             if (0 == y)

  10:             {

  11:                 throw new FaultException<string>("被除数y不能为零!", "被除数y不能为零!");

  12:             }

  13:             return x / y;

  14:         }

  15: }

  16: }

在那种气象下,你须求做的照旧是在相应的操作上边,通过应用FaultContractAttribute个性钦点String类型作为其DetailType,如上面包车型地铁代码所示:

   1: using System.ServiceModel;

   2: namespace Artech.WcfServices.Contracts

   3: {

   4:     [ServiceContract(Namespace = "http://www.artech.com/")]

   5:     public interface ICalculator

   6:     {

   7:         [OperationContract]

   8:         [FaultContract(typeof(string))]

   9:         int Divide(int x, int y);

  10:     }   

  11: }

从FaultContractAttribute的概念大家能够见到,该天性能够在同三个目的对象方面往往行使(AllowMultiple

true)。那也很好精晓:对于同2个服务操作,只怕持有差别的不胜处境,在分裂的状态下,须求抛出不一致的百般。

   1: [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]

   2: public sealed class FaultContractAttribute : Attribute

   3: {    

   4:     //省略成员

   5: }

唯独,假如您在同2个操作方法下面使用了多了FaultContractAttribute脾气的时候,要求根据一多元的条条框框,我们将在《WCF基本至极处理格局(下篇)》中开始展览依次介绍。

作者:Artech
出处:http://artech.cnblogs.com
正文版权归作者和网易共有,欢迎转发,但未经小编同意必须保留此段证明,且在小说页面显著地方给出最初的作品连接,不然保留追究法律义务的职责。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图