WCF中数据契约之已知类型的几种公开方式
WCF中传输的数据不想传统的面向对象编程,它只传递了一些对象的属性,但是自身并不知道自己属于什么对象,所以,他没有子类和父类的概念,因而也就没有Is-a的关系,所以在WCF中,如果想维持这种继承关系,就需要做一些特殊的处理了。
假设有如下定义,
namespace KnownTypeExampleInterface
{
[DataContract]
public class Employee
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Age { get; set; }
}
[DataContract]
public class Manager:Employee
{
[DataMember]
public int OfficeId { get; set; }
}
public interface IHumanResourceService
{
List<Employee> GetAllEmployees();
}
}
这样,在调用端是无法得到manager的OfficeId的,因为在服务定义中并不知道有Manager类的存在。
解决这种问题的有如下几种方法
代码中定义
解决这种问题的一种方法是使用KnownTypeAttribute告诉WCF存在Manager的信息:
[DataContract]
[KnownType(typeof(Manager))]
public class Employee
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Age { get; set; }
}
这样,在宿主端,会影响到所有的契约与操作,也就是说使用了Employee的服务契约或者操作,最终在契约中都会存在Manager的定义。
但是如果不想Manager暴露给所有的使用Employee的服务,则可以使用ServiceKnownTypeAttribute应用在服务定义或者操作定义上,这样就只会有服务或者操作才能够接受Manager子类了。
public interface IHumanResourceService
{
List<Employee> GetAllEmployees();
[ServiceKnownType(typeof(Manager))]
void AddEmployee(Employee employee);
}
配置中定义
在代码中定义的有一个主要的缺陷,就是客户端必须事先知道这些子类,添加一个子类就得修改一次代码,重新编译,部署,所以WCF也允许允许通过配置文件的方式添加这些子类。
<system.runtime.serialization>
<dataContractSerializer>
<declaredTypes>
<add type="Employee,KnownTypeExampleInterface,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null">
<knownType type="Manager,KnownTypeExampleInterface,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"/>
</add>
</declaredTypes>
</dataContractSerializer>
</system.runtime.serialization>
宿主端使用解析器
另外一种清大的方法就是使用数据契约解析器,它能够自动化的去解析这些子类,而不需要手动的去添加标签或者修改配置文件。
实现这种数据契约解析器的方法
在WCF中,存在DataContractResolver类,可以在这个类中提供一个维护了唯一标识符和类型之间的映射关系字典,在序列化这个类型时,需要提供一个唯一的标识符作为键形成键与类型的映射关系,WCF会在反序列化期间提供这些键。参照上文中的数据契约,相对应的解析器定义为:
public abstract class ManagerDataContractResolver:DataContractResolver
{
private string Namespace
{
get { return typeof (Manager).Namespace ?? "global"; }
}
private string Name
{
get { return typeof (Manager).Name; }
}
public override Type ResolveName(string typeName, string typeNamespace, Type declaredType, DataContractResolver knownTypeResolver)
{
if (typeName == this.Name && typeNamespace == this.Namespace)
{
return typeof (Manager);
}
else
{
return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null);
}
}
public override bool TryResolveType(Type type, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
{
if (type == typeof (Manager))
{
XmlDictionary dic = new XmlDictionary();
typeName = dic.Add(this.Name);
typeNamespace = dic.Add(this.Namespace);
return true;
}
else
{
return knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace);
}
}
}
自定义的解析器定义完成,之后需要分别在代理端和宿主端安装解析器,
在ServiceEndpoint中有一个类型为ContractDascription的Contract属性,它是一个操作描述的集合,每一个描述操作描述(OperationDescription)都包含一个类型为IOperationBehavior类型的行为集合,而每一个行为又包含一个DataContractResolver属性,这个属性默认为null,就是在这里,可以设置我们自定义的解析器。
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof (HumanResourceService));
foreach (ServiceEndpoint endpoint in host.Description.Endpoints)
{
foreach (OperationDescription operation in endpoint.Contract.Operations)
{
DataContractSerializerOperationBehavior behavior =
operation.OperationBehaviors.FirstOrDefault(
x => x.GetType() == typeof (DataContractSerializerOperationBehavior)) as DataContractSerializerOperationBehavior;
behavior.DataContractResolver = new ManagerDataContractResolver();
}
}
host.Open();
Console.WriteLine("Host Running!");
Console.ReadKey();
host.Close();
}
而在代理一端,可以使用同样的方式安装解析器,不在赘述!
好了,今天就到这里了,明天去办居(zan)住证,明天开始我也是天津市合法居民了。希望得到您的推荐与点赞,满足虚荣心之后定会贡献更多给IT事业哦
WCF中数据契约之已知类型的几种公开方式的更多相关文章
- WCF 已知类型和泛型解析程序 KnownType
		
数据协定继承 已知类型和泛型解析程序 Juval Lowy 下载代码示例 自首次发布以来,Windows Communication Foundation (WCF) 开发人员便必须处理数据协定继承方 ...
 - WCF数据契约代理和已知类型的使用
		
using Bll; using System; using System.CodeDom; using System.Collections.Generic; using System.Collec ...
 - WCF技术剖析之十三:序列化过程中的已知类型(Known Type)
		
原文:WCF技术剖析之十三:序列化过程中的已知类型(Known Type) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话) ...
 - C# 序列化过程中的已知类型(Known Type)
		
WCF下的序列化与反序列化解决的是数据在两种状态之间的相互转化:托管类型对象和XML.由于类型定义了对象的数据结构,所以无论对于序列化还是反序列化,都必须事先确定对象的类型.如果被序列化对象或者被反序 ...
 - WCF 之 已知类型(KnownType)
		
已知类型(Known types)允许在服务契约中使用多态的行为,在服务操作中暴露基本类型.将已知类型(known types)相关到基本类型(基类类型)自身;特定操作;整个服务契约采用属性声明或者配 ...
 - 重温WCF之数据契约和序列化(四)
		
一.数据契约 1.使用数据协定可以灵活控制哪些成员应该被客户端识别. [DataContract] public class Employee { [DataMember] public string ...
 - WCF之数据契约
		
从抽象层面看,WCF能够托管CLR类型(接口和类)并将它们公开为服务,也能够以本地CLR接口和类的方式使用服务.然而,CLR类型却属于.NET的特定技术.由于面向服务的一个核心原则就是在跨越服务边界时 ...
 - java基础 File与递归练习 使用文件过滤器筛选将指定文件夹下的小于200K的小文件获取并打印按层次打印(包括所有子文件夹的文件) 多层文件夹情况统计文件和文件夹的数量 统计已知类型的数量 未知类型的数量
		
package com.swift.kuozhan; import java.io.File; import java.io.FileFilter; /*使用文件过滤器筛选将指定文件夹下的小于200K ...
 - js中Json字符串如何转成Json对象(4种转换方式)
		
js中Json字符串如何转成Json对象(4种转换方式) 一.总结 一句话总结:原生方法(就是浏览器默认支持的方法) 浏览器支持的转换方式(Firefox,chrome,opera,safari,ie ...
 
随机推荐
- 8、RabbitMQ-消息的确认机制(生产者)
			
RabbitMQ 之消息确认机制(事务+Confirm) https://blog.csdn.net/u013256816/article/details/55515234 概述: 在 Rabbitm ...
 - java 静态相关内容
			
一般情况下,如果有些代码必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的;需要在项目启动的时候就初始化,在不创建对象的情况下,其他程序来调用的时候,需要使用静态方法,这种代码 ...
 - 跳转到系统设置界面 iOS
			
NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString]; if ([[UIApplication sharedApp ...
 - PAT——1042. 字符统计
			
请编写程序,找出一段给定文字中出现最频繁的那个英文字母. 输入格式: 输入在一行中给出一个长度不超过1000的字符串.字符串由ASCII码表中任意可见字符及空格组成,至少包含1个英文字母,以回车结束( ...
 - SDOI2018 二轮培训划水记
			
\(\mathcal{Day -1}\) 嗯,虽然说\(rqy\)看我们这么懵O,并不建议我们去掺和这种神仙打架,但是为了逃文化课学习OI并参观膜拜各路神仙,我毅然决然地选择去参加这次培训-- 这次一 ...
 - 如何在localStorage中存取数组
			
默认localStorage只能存取字符串 那么如何存取数组呢 let newlist = [] localStorage.setItem('recent', JSON.stringify(newli ...
 - EJB到底是什么?---通俗易懂,简单明了
			
EJB到底是什么? 1. 我们不禁要问,什么是"服务集群"?什么是"企业级开发"? 既然说了EJB 是为了"服务集群"和"企业 ...
 - 进程通信-Queue
			
进程通信-Queue Queue消息队列是python进程通信的其中一种方式.需要引入multiprocessing包中的Queue函数(这是函数,不是类). 有一个queue包,里面也有Queue, ...
 - iOS中UITextField常用设置和方法
			
//初始化textField并设置位置及大小 UITextField *text = [[UITextField alloc]initWithFrame:CGRectMake(, , , )]; // ...
 - Scanner(基本用法初学)
			
package day01; import java.util.Scanner; public class Case05 { public static void main(String[] args ...