KnownTypeAttribute 类概述
- 在数据到达接收终结点时,WCF 运行库尝试将数据反序列化为公共语言运行库 (CLR) 类型的实例。通过首先检查传入消息选择为反序列化而实例化的类型,以确定消息内容遵循的数据协定。然后反序列化引擎尝试查找实现与消息内容兼容的数据协定的 CLR 类型。反序列化引擎在此过程中允许的侯选类型集称为反序列化程序的“已知类型”集。
- 让反序列化引擎了解某个类型的一种方法是使用 KnownTypeAttribute。不能将属性应用于单个数据成员,只能将它应用于整个数据协定类型。将属性应用于可能为类或结构的“外部类型”。在其最基本的用法中,应用属性会将类型指定为“已知类型”。只要反序列化外部类型的对象或通过其成员引用的任何对象,这就会导致已知类型成为已知类型集的一部分。可以将多个 KnownTypeAttribute 属性应用于同一类型。
以下情形需要使用KnownTypeAttribute修饰数据协定
- 已发送的数据协定源自预期的数据协定。在该情况下,传输的数据没有与接收终结点所预期相同的数据协定。
- 要传输的信息的声明类型是接口,而非类、结构或枚举。因此,无法预先知道实际发送了实现接口的哪个类型,接收终结点就无法预先确定已传输数据的数据协定。
- 要传输的信息的声明类型是 Object。由于每个类型都继承自 Object,而且无法预先知道实际发送了哪个类型,因此接收终结点无法预先确定已传输数据的数据协定。这是第一个项的特殊情况:每个数据协定都源自为 Object 生成的默认空数据协定。
- 某些类型(包括 .NET Framework 类型)具有上述三种类别之一中的成员。例如,Hashtable 使用 Object 在哈希表中存储实际对象。在序列化这些类型时,接收方无法预先确定这些成员的数据协定。
数据协定使用KnownType示例
- 解决方案如下:
- 工程结构说明:
- 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;
namespace Service
{
[ServiceContract]
public interface IUserInfo
{
[OperationContract]
Person GetInfo(int id,string name);
[OperationContract]
Person GetInfoEx(int id, string name);
}
[DataContract]
[KnownType(typeof(User))]
public class Person
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
public Person(int id, string name)
{
this.ID = id;
this.Name = name;
}
}
[DataContract]
public class User:Person
{
public User(int id, string name): base(id,name){}
[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代码如下:
using System; using System.ServiceModel; using Service; namespace Host { class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(UserInfo))) { host.Opened += delegate { Console.WriteLine("服务已经启动,按任意键终止!"); }; host.Open(); Console.Read(); } } } }