我正在学习WCF并且不了解KnowTypeAttribute的真正优势.有人可以解释我为什么需要它吗?
Mar*_*ell 22
DataContractSerializer是基于契约的,这意味着它不依赖于任何特定类型的模型.它只有数据(通常是xml).这意味着,如果你有一个像这样的模型:
Customer
SuperCustomer : Customer
AwesomeCustomer : Customer
Run Code Online (Sandbox Code Playgroud)
那么序列化器需要提前知道每种类型在数据中看到的含义; 否则它将不知道要创建什么类型.这可以通过多种方式完成,其中最简单的方法是KnownTypeAttribute.
考虑替代方案; 所有序列化程序都知道是"客户",它希望<customer>...</customer>
在某些xml中看到它.相反,它得到了其他东西(它无关紧要,但让我们说<superCustomer>...</superCustomer>
.现在它做了什么?它是否开始寻找可能看起来类型?这是非常不精确和风险的.还要考虑,它需要能够生成这个数据的WSDL/MEX导出 - 如果它只知道是"客户",则无法警告调用者也期望SuperCustomer/AwesomeCustomer - 这意味着WSDL/MEX不完整且无用.
XmlSerializer(XmlIncludeAttribute)和protobuf-net(ProtoIncludeAttribute)使用相同的方法,可能是我最基于合同的序列化程序.
替代方案是基于类型的序列化器(BinaryFormatter,NetDataContractSerializer等) - 其中包括数据中的类型,意思是Your.Namespace.Type, Your.Assembly, blah
- 这意味着它不需要事先知道(因为它在数据中是显式的),但也意味着它不可能适用于不同的模型(或实际上,跨平台).
通过KnownTypeAttribute,您可以为给定的数据协定指定可接受的派生类.它指定在序列化或反序列化给定类型时应由DataContractSerializer识别的类型.
一个简单的例子.
[ServiceContract()]
interface ITaskManager
{
[OperationContract()]
MyCollection<Task> GetTaskByAssignedName(string name);
}
[DataContract()]
[KnownType(typeof(DerivedTask))]
class Task
{
}
[DataContract()]
class DerivedTask
{
}
Run Code Online (Sandbox Code Playgroud)
在服务契约中使用多态类型时,需要使用KnownTypeAttribute,因为多态性超出了服务方向的范例.
将KnownTypeAttribute属性应用于类型,以指示在序列化或反序列化应用该属性的类型的实例时应识别的DataContractSerializer类型.理解数据协定的其他序列化程序也可以识别此属性.
请查看此处了解更多详情.
此属性用于在服务的元数据中包含其他类,以便客户端可以看到它们.我们举个例子如下:
[DataContract]
public class BaseModel
{
[DataMember]
public string Id { get; set; }
}
[DataContract]
public class ChildModel: BaseModel
{
[DataMember]
public string Foo { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
以及以下服务合同:
[ServiceContract]
public interface IMyService
{
[OperationContract]
BaseModel Get();
}
Run Code Online (Sandbox Code Playgroud)
并且你实现它像这样:
public class MyService: IMyService
{
public BaseModel Get()
{
return new ChildModel();
}
}
Run Code Online (Sandbox Code Playgroud)
现在,当WCF公开此服务的元数据时,它会查看服务契约和涉及的操作,因此它会发现返回BaseModel类型的Get操作.因此,BaseModel类会自动在元数据中公开.问题是,当您尝试调用服务时,实际的实现返回一个ChildModel
WCF,不知道.该服务的客户端既不具备此类型的知识.
因此,您需要明确指出您在实现中使用的此类,但不是合同的一部分.这可以通过使用KnownType属性来完成:
[DataContract]
[KnownType(typeof(ChildModel))]
public class BaseModel
{
[DataMember]
public string Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
指定此已知类型的另一种方法是使用配置文件:
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="MyCompany.BaseModel, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=XXXXXX, processorArchitecture=MSIL">
<knownType type="MyCompany.ChildModel, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=XXXXXX, processorArchitecture=MSIL"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
8469 次 |
最近记录: |