唯独,“尽管已知类型对于另一个顺序集而言是中间(internal)类型,要添加一个已知类型,唯有应用安插文件宣称它。”

WCF的系列化使用了.NET平台本身帮助的种类化机制,因而那里不再另行。

多少契约与劳务契约相似,数据成员或数额契约的拜访限定与WCF之间并不曾因果关系。数据契约完全可以涵盖私有数据成员等中间类型:
[DataContract]
struct Contact
{
   [DataMember]
   string m_FirstName;

数量契约是劳务期间传递的数码。由于必须辅助跨进度,乃至于跨机器的传递,WCF必须对数码举办分外规的处理,否则无法落到实处数量的传递。在.NET
Remoting与Web
Service中,对数码的处理方式寻常是选取种类化的不二法门,WCF同样沿袭了这一做法,但为了更好的反映面向服务的特质,又专门引入了多少契约(DataContract)。其它,WCF还引入了音信契约(MessageContract),但本书没有介绍。

   [DataMember]
   public string LastName
   {
      get
      {
         return LastNameField;
      }
      set
      {
         LastNameField = value;
      }
   }
}
它会将字段名作为属性名,而导入的概念中,则在属性名后拉长Field后缀作为字段名。但大家也可以手工修改客户端的概念。

那么在拍卖多少契约Contact的劳务契约中,倘若契约的操作必要以抽象方式,定义IContact类型的参数,就不能够不运用ServiceKnownType特性指名其达成类Contact,如下所示:
[ServiceContract]
[ServiceKnownType(typeof(Contact))]
interface IContactManager
{
   [OperationContract]
   void AddContact(IContact contact);

Contact contact = new Customer(  );
contact.FirstName = “Juval”;
contact.LastName = “Lowy”;

不过,大家不可以以求实的数目契约类型Contact,来替换原来的object类型。因为替换为现实的数额契约类型,则客户端的劳务契约就与服务端的劳动契约不包容了。所以,上边的定义是不对的:
[ServiceContract]
public interface IContactManager
{
    [OperationContract]
    void AddContact(Contact contact);
   
    [OperationContract]
    Contact[] GetContacts(  );
}

“不要将DataMember特性既应用到属性上,又采用到相呼应的字段上,那会招致导入的成员定义再一次。”

   [DataMember]
   string m_LastName;
}

   //Cannot return Customer objects here:
   [OperationContract]
   Contact[] GetContacts(  );
}
借使客户端同时定义了一个Customer类:

[DataContract]
class Customer : Contact
{…}
 
[ServiceContract]
interface IContactManager
{
   [OperationContract]
   [ServiceKnownType(typeof(Customer))]
   void AddContact(Contact contact);

   [DataMember]
   public string FirstName
   {
      get
      {
         return FirstNameField;
      }
      set
      {
         FirstNameField = value;
      }
   }

比方数据契约的多少成员为个人的,导入的客户端定义会自动修改为国有的。“当DataMember特性应用到属性上时(不管是劳务依然客户端),该属性必须具备get和set访问器。如果没有,在调用时就会抛出InvalidDataContractException非凡。因为当属性自身就是数量成员时,WCF会在连串化和反系列化时利用该属性,使开发者可以将定制逻辑应用到属性中。”

注意,此时不可以利用KnownType特性,将其一向动用到IContact接口上,因为导出的元数据不可能包涵接口本身。

第一WCF并不匡助Liskov替换原则(LSP),“默许情形下,大家不可能用数据契约的子类去替换基类。”
考虑如下的服务契约:
[ServiceContract]
interface IContactManager
{
   //Cannot accept Customer object here:
   [OperationContract]
   void AddContact(Contact contact);

[DataContract]
class Customer : Contact
{
   [DataMember]
   public int OrderNumber;
}
以下代码能够成功通过编译,但在运作时却会破产:

.NET提供的连串化机制尽管可以应付SOA的需求,但照旧存在诸多不足之处。本书总括了Serializable的症结:
“Serializable所指代的涵义是种类的有所成员都是可体系化的,那么些分子是构成类型数据样式的一有些。然则,更好的办法是可以提供一种大庭广众参加(Opt-In)途径,唯有那多少个契约的开发者明确涵盖的成员才应该松开数据契约中。Serializable特性强制要求数据类型是可序列化的,从而使得项目可以被看成契约操作的参数,但它却一筹莫展兑现项目标服务特性(具有成为WCF操作参数的力量)与系列化能力之间的任务分开。Serializalbe特性不援救项目名和分子名的别名,也无法将一个新品类映射为预约义的数据契约。由于Serializable特性可以平昔操作成员字段,使得封装了字段访问的属性形同虚设。访问字段的最好格局是因而品质添加它们的值,而Serializable却破坏了质量的封装性。最终,Serializable特性并不曾一直帮忙版本控制(Versioning),而版本控制的音信却是格式器期望获得的。无疑,它导致了版本控制的处理变得吃力。”

导出定义中,将动用到契约的ServiceKnownType特性应用到了各种操作上,并且为各种操作都指定了现实的数量契约子类以及一个object[]项目。越发要注意,在操作的再次来到值与参数中,原来的IContact类型全体被转换为了object类型。原因在于,客户端并没有IContact接口的定义。基于object的契约定义无疑不抱有类型安全性。

WCF提供的数据契约DataContract基本上解决了上述的题目。日常,DataContract必须与DataMember结合使用。唯有接纳了DataMember特性的习性才被公开到元数据中。即便DataMember特性也可以使用到对象的字段上,但WCF并不推荐那样做,原因与类的设计原则一致。

为驾驭决这一题材,WCF提供了布置已知类型的章程。例如:
<system.runtime.serialization>
   <dataContractSerializer>
      <declaredTypes>
         <add type = “Contact,Host,Version=1.0.0.0,Culture=neutral,
                                                             
PublicKeyToken=null”>
            <knownType type =
“Customer,MyClassLibrary,Version=1.0.0.0,
                                            
Culture=neutral,PublicKeyToken=null”/>
         </add>
      </declaredTypes>
   </dataContractSerializer>
</system.runtime.serialization>

解决办法自然是在客户端中追加IContact接口的定义。如此,客户端定义就可以修改为:
[ServiceContract]
public interface IContactManager
{
    [OperationContract]
    [ServiceKnownType(typeof(Contact))]
    void AddContact(IContact contact);
   
    [OperationContract]
    [ServiceKnownType(typeof(Contact))]
    IContact[] GetContacts(  );
}

就算DataMember特性被一贯使用到字段上,在导入的客户端定义照旧会以属性来代表。如下的多少契约定义:
[DataContract]
struct Contact
{
   [DataMember]
   public string FirstName;

在WCF的数码契约中,很显然地反映出WCF还不可见统统襄助面向对象的设计思想。在第2章对劳务契约的描述中,对契约的接续层级的处理格局来看,已经呈现了这一缺点的线索。而对此数据契约而言,更是愈发揭发了如此的弱项。

历史观的格式器不可能种类化只标记了DataContract特性的品类。要系列化那样的类型,必须同时利用DataContract特性和Serializable特性。对于这么种类变更的传输型表示方式(Wire
Representation),就似乎仅仅使用了DataContract特性一般,同时,大家依然必要为成员添加DataMember特性。

服务端的定义无疑符合面向接口编程思想,除了伸张了ServiceKnownType之外,整个安顿还算优雅。可是根据那样的概念所导出的劳务契约,却未免显得大失所望,如下所示:
[ServiceContract]
public interface IContactManager
{
    [OperationContract]
    [ServiceKnownType(typeof(Contact))]
    [ServiceKnownType(typeof(object[]))]
    void AddContact(object contact);
   
    [OperationContract]
    [ServiceKnownType(typeof(Contact))]
    [ServiceKnownType(typeof(object[]))]
    object[] GetContacts(  );
}

留意上述的安顿文件中,大家配备的已知类型必须是体系的fullname。蕴含取名空间、版本号、Culture等。尽管那种方法可以幸免在增多子类的景况下,修改代码、重新编译和重新陈设,但无疑加剧了开发者的负责,更加是对安顿文件的管制以及中期的爱慕。

WCF引入的服务已知类型,比较已知类型而言,有早晚程度的改良。因为它可以将父类与子类在层级上的耦合度缩短到方法级上。但诸如此类的耦合,如故是不足接受的。例如:
[DataContract]
class Contact
{…}

简单的说,在WCF中要贯彻面向对象的多态,还不许成功最佳。如若可以将KnownType特性应用到子类上,为子类指名它所继承的父类,无疑进一步有利类的恢弘。遗憾的是WCF未能成功那或多或少。

如若数额契约本身已毕了一个接口,情状就变得有趣了。从服务端的概念来看,那样的数据契约仍是可以够通过劳动已知类型在服务契约上指定完结了数量契约接口的子数据契约类型。例如,数据契约Contact类完结了接口IContact:
interface IContact
{  
   string FirstName
   {get;set;}
   string LastName
   {get;set;}
}
[DataContract]
class Contact : IContact
{…}

   [OperationContract]
   Contact[] GetContacts(  );
}
理所当然,服务已知类型也足以使用到契约接口上,此时,该契约以及落到实处该契约的装有服务包蕴的装有操作都能够收到已知的子类。

即便如此WCF引入了Known
Types(已知类型)来化解这一标题,但是对于明白面向对象思想的设计者而言,那样的统筹无疑会引入父类与子类之间的耦合度。因为在大家设计父类的时候,就无法不优先知道子类的定义。当大家需求扩展子类时,还须要修改父类的定义。

本书的第3章重点教学了有关数据契约的知识。“从空洞层面看,WCF可以托管CLR类型(接口和类)并将它们公开为劳动,也可以以当地CLR接口和类的艺术选取劳务。WCF服务的操作接收和重返诸如int和string的CLR类型,WCF客户端则传递和拍卖回来的CLR类型。但是,CLR类型却属于.NET的一定技术。由于面向服务的一个焦点标准就是在跨越服务边界时,服务不可知揭露它们的落成技术。因而,不管客户端接纳了何种技术,它都可以与服务交互。明显,这就代表WCF分歧意在当先服务边界时当面CLR数据类型。我们需求找到一种方法,完毕CLR数据类型与业内的与平台非亲非故的表示方式之间的转换。这样的象征方式就是依照XML的体裁或音讯集(Infoset)。其余,服务须求一种标准的法子申明两者之间的变换。那些措施就是本章所要介绍的宗旨——数据契约。本章的首先局地介绍了多少契约启用类型封送(Type
Marshaling)与转换的主意,以及哪些通过基础架构处理类的层级与数量契约的版本控制。第二有些则介绍了怎么将分裂的.NET类型,例如枚举、委托、数据表以及汇集,作为数据契约使用。”

   [DataMember]
   public string LastName;
}
导入的客户端定义为:
[DataContract]
public partial struct Contact
{
   string FirstNameField;
   string LastNameField;

   [OperationContract]
   IContact[] GetContacts(  );
}

设若服务端的多少被标记为Serializable特性,在导入那样的概念时,会接纳DataContract。而且“对于每一个可系列化的分子,不管是国有的要么个体的,都是数据成员。” 

ContactManagerClient proxy = new ContactManagerClient(  );
//Service call will fail:
proxy.AddContact(contact);
proxy.Close(  );
因为在那一个例子中,大家传递了一个Customer对象,而不是Contact对象。由于劳动不能识别Customer对象,也就不能够反体系化它所接收到的Contact对象。

相关文章

网站地图xml地图