KnownTypeAttribute 类概述

  • 在数据到达接收终结点时,WCF 运行库尝试将数据反序列化为公共语言运行库 (CLR) 类型的实例。通过首先检查传入消息选择为反序列化而实例化的类型,以确定消息内容遵循的数据协定。然后反序列化引擎尝试查找实现与消息内容兼容的数据协定的 CLR 类型。反序列化引擎在此过程中允许的侯选类型集称为反序列化程序的“已知类型”集。
  • 让反序列化引擎了解某个类型的一种方法是使用 KnownTypeAttribute。不能将属性应用于单个数据成员,只能将它应用于整个数据协定类型。将属性应用于可能为类或结构的“外部类型”。在其最基本的用法中,应用属性会将类型指定为“已知类型”。只要反序列化外部类型的对象或通过其成员引用的任何对象,这就会导致已知类型成为已知类型集的一部分。可以将多个 KnownTypeAttribute 属性应用于同一类型。

以下情形需要使用KnownTypeAttribute修饰数据协定

  • 已发送的数据协定源自预期的数据协定。在该情况下,传输的数据没有与接收终结点所预期相同的数据协定。
  • 要传输的信息的声明类型是接口,而非类、结构或枚举。因此,无法预先知道实际发送了实现接口的哪个类型,接收终结点就无法预先确定已传输数据的数据协定。
  • 要传输的信息的声明类型是 Object。由于每个类型都继承自 Object,而且无法预先知道实际发送了哪个类型,因此接收终结点无法预先确定已传输数据的数据协定。这是第一个项的特殊情况:每个数据协定都源自为 Object 生成的默认空数据协定。
  • 某些类型(包括 .NET Framework 类型)具有上述三种类别之一中的成员。例如,Hashtable 使用 Object 在哈希表中存储实际对象。在序列化这些类型时,接收方无法预先确定这些成员的数据协定。

数据协定使用KnownType示例

  • 解决方案如下:

  

  • 工程结构说明:
  1. Service:类库程序,WCF服务端程序。在服务协定接口IUserInfo.cs中定义数据协定类Person,再定义一个数据协定类User。User派生至Person,继承基类Person的构造方法,定义新的属性成员SayHello。定义操作协定GetInfo和GetInfoEx,两者返回类型都为Person。在UserInfo.cs中实现数据协定,在GetInfo中,我们返回Person对象类型,在GetInfoEx中我们返回派生类User类型。由于在GetInfoEx中我们需要传递派生类User类型,所以要在基类数据协定Person上面加上KnownType(typeof(User))特性标记,这样User就能够客户端进行反序列化,供客户端使用。

IUserInfo.cs代码如下: 

using System.ServiceModel;
using System.Runtime.Serialization;
using System;

  1.  

namespace Service
{
[ServiceContract]
public interface IUserInfo
{
[OperationContract]
Person GetInfo(int id,string name);

  1.  

[OperationContract]
Person GetInfoEx(int id, string name);
}

  1.  

[DataContract]
[KnownType(typeof(User))]
public class Person
{
[DataMember]
public int ID { get; set; }

  1.  

[DataMember]
public string Name { get; set; }

  1.  

public Person(int id, string name)
{
this.ID = id;
this.Name = name;
}
}

  1.  

[DataContract]
public class User:Person
{
public User(int id, string name): base(id,name){}

  1.  

[DataMember]
public string SayHello
{
get { return "Hello:" + Name; }
set { throw new NotImplementedException(); }
}
}

}

  UserInfo.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Service
{
public class UserInfo:IUserInfo
{
public Person GetInfo(int id, string name)
{
return new Person(id, name);
}

public Person GetInfoEx(int id, string name)
{
return new User(id, name);
}
}
}

  2.  Host:控制台应用程序,服务承载程序。添加对程序集Service的引用,完成以下代码,寄宿服务。Program.cs代码如下:

  

  1. using System;
  2. using System.ServiceModel;
  3. using Service;
  4.  
  5. namespace Host
  6. {
  7. class Program
  8. {
  9. static void Main(string[] args)
  10. {
  11. using (ServiceHost host = new ServiceHost(typeof(UserInfo)))
  12. {
  13. host.Opened += delegate { Console.WriteLine("服务已经启动,按任意键终止!"); };
  14. host.Open();
  15. Console.Read();
  16. }
  17. }
  18. }
  19. }

  App.config代码如下:

  

  1. <?xml version="1.0"?>
  2. <configuration>
  3. <system.serviceModel>
  4.  
  5. <services>
  6. <service name="Service.UserInfo" behaviorConfiguration="mexBehavior">
  7. <host>
  8. <baseAddresses>
  9. <add baseAddress="http://localhost:1234/UserInfo/"/>
  10. </baseAddresses>
  11. </host>
  12. <endpoint address="" binding="wsHttpBinding" contract="Service.IUserInfo" />
  13. <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  14. </service>
  15. </services>
  16.  
  17. <behaviors>
  18. <serviceBehaviors>
  19. <behavior name="mexBehavior">
  20. <serviceMetadata httpGetEnabled="true"/>
  21. <serviceDebug includeExceptionDetailInFaults="true"/>
  22. </behavior>
  23. </serviceBehaviors>
  24. </behaviors>
  25. </system.serviceModel>
  26. </configuration>

  我们通过svcutil.exe工具生成客户端代理类和客户端的配置文件

  svcutil.exe是一个命令行工具,位于路径C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin下,我们可以通过命令行运行该工具生成客户端代理类

  • 在运行中输入cmd打开命令行,输入 cd C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin
  • 输入svcutil.exe /out:f:\UserInfoClient.cs /config:f:\App.config http://localhost:1234/UserInfo

  3.  Client:控制台应用程序,客户端调用程序。将生成的UserInfoClient.cs和App.config复制到Client的工程目录下,完成客户端调用代码。Program.cs的代码如下:

  1.  

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Service;

  1.  

namespace Client
{
class Program
{
static void Main(string[] args)
{
try
{
UserInfoClient proxy = new UserInfoClient();
Person P1 = proxy.GetInfo(1,"JACK");
Person P2 = proxy.GetInfoEx(2, "TOM");
Console.WriteLine("{0,-10}{1,-20}", "ID", "Message");

  1.  

Console.WriteLine("{0,-10}{1,-20}", P1.ID, P1.Name);
if (P2 is User)
{
Console.WriteLine("{0,-10}{1,-20}", ((User)P2).ID,((User)P2).SayHello);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}

  1.  

Console.Read();
}
}
}

  4.  程序运行效果如下:

  

总结:

  • 从上面的示例可以看出,如果我们需要使用的数据契约类派生出了子类,并且在操作协定中使用了子类数据契约类型和基类数据契约类型,那我们必须为子类和基类成员添加必要的DataContract和DataMember修饰,而且还需要在基类数据契约上加上KnownType来告知客户端需要反序列化子类的成员。

WCF初探-18:WCF数据协定之KnownType的更多相关文章

  1. 我们一起学习WCF 第五篇数据协定和消息协定

    A:数据协定(“数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每个参数或 ...

  2. WCF学习心得------(六)数据协定

    --前言 最近各种事忙的把之前的WCF学习给耽误了一些,今天抽时间把之前的学习内容给总结了一下,因为知识点比较细碎没有做太多的练习示例,只是对其中关键的知识点做了总结,希望可以对大家有所帮助. 第六章 ...

  3. WCF初探文章列表

    WCF初探-1:认识WCF WCF初探-6:WCF服务配置 WCF初探-2:手动实现WCF程序 WCF初探-7:WCF服务配置工具使用 WCF初探-3:WCF消息交换模式之单向模式 WCF初探-8:W ...

  4. WCF初探-16:WCF数据协定之基础知识

    数据协定概念 “数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每一个做数 ...

  5. WCF初探-17:WCF数据协定之等效性

    数据协定等效性特点概述 对于客户端要将某种类型的数据成功发送到服务,或者服务要将数据成功发送到客户端的情况,接收端上并不一定必须存在此发送数据类型. 唯一的要求是两种类型的数据协定应该等效. 要使数据 ...

  6. WCF初探-14:WCF服务协定

    前言: 在前面的文章中,我们定义的服务协定上都会有一个ServiceContract的特性来修饰,这是因为服务契约的实现要靠ServiceContractAttribute 属性定义,然后使用一个或多 ...

  7. WCF初探-20:WCF错误协定

    WCF错误协定概述 在所有托管应用程序中,处理错误由 Exception 对象表示. 在基于 SOAP 的应用程序(如 WCF 应用程序)中,服务方法使用 SOAP 错误消息来传递处理错误信息. SO ...

  8. WCF基础之数据协定

    数据协定最重要的当然就是DataContract和DataMember.这两个特性能应用到类.结构和枚举.这个两个特性跟服务契约的特点是一样的,只有被DataContract标记的类和类中被标记Dat ...

  9. WCF初探-19:WCF消息协定

    WCF消息协定概述 在生成 WCF应用程序时,开发人员通常会密切关注数据结构和序列化问题,而不必关心携带数据的消息结构. 对于这些应用程序,为参数或返回值创建数据协定的过程很简单.但是,有时完全控制 ...

随机推荐

  1. -XX:+TraceClassLoading 监控类的加载

    -XX:+TraceClassLoading –监控类的加载 •[Loaded java.lang.Object from shared objects file] •[Loaded java.io. ...

  2. 夺命雷公狗-----React---5--props对象的传递

    提示:props的值是不可以改变的... <!DOCTYPE html> <html lang="en"> <head> <meta ch ...

  3. delphi TIdHTTP Post乱码问题

    这里主要说的是中文乱码的问题 1. 发过去的是乱码如下处理, 服务器采用的是UFT-8编码的情况下 uses  HTTPApp;      sPost := HTTPEncode(UTF8Encode ...

  4. Linux按键驱动程序设计--从简单到不简单【转】

    本文转载自:http://blog.csdn.net/coding__madman/article/details/51399353 混杂设备驱动模型: 1. 混杂设备描述 在Linux系统中,存在一 ...

  5. [转]SOCKET通信中TCP、UDP数据包大小的确定

    TCP.UDP数据包大小的确定 UDP和TCP协议利用端口号实现多项应用同时发送和接收数据.数据通过源端口发送出去,通过目标端口接收.有的网络应用只能使用预留或注册的静态端口:而另外一些网络应用则可以 ...

  6. 13.KVM安装之网桥

    安装必须的几个库和软件(最好下载一个163的yum源,速度快点) $ yum -y install kvm python-virtinst libvirt tunctl bridge-utils vi ...

  7. Tortoise 下修改服务器路径(Relocate与Switch)

    今天遇到SVN的路径变化,要在客户端修改服务器的下载路径,当初想直接删除重新checkout,后来想着还要重建项目比较麻烦,就找找修改服务器路径的方法.网上基本说的都是右键-->Relocate ...

  8. 【PHP】基于ThinkPHP框架搭建OAuth2.0服务

    [PHP]基于ThinkPHP框架搭建OAuth2.0服务 http://leyteris.iteye.com/blog/1483403

  9. Head First 设计模式 --6 命令模式

    命令模式:将"请求"封装成对象,以便使用不同的请求,队列或者日志来参数化其他对象.命令模式也支持可撤销的操作.用到的原则:1.封装变化2.组合优于继承3.针对接口编程,不能针对实现 ...

  10. android通知栏Notification点击,取消,清除响应事件

    主要是检测android通知栏的三种状态的响应事件 这次在实现推送需求的时候,要用到android通知栏Notification点击后进入消息页面,因为要实现一个保存推送用户名字的功能,我在点击后处理 ...