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中数据契约之已知类型的几种公开方式的更多相关文章

  1. WCF 已知类型和泛型解析程序 KnownType

    数据协定继承 已知类型和泛型解析程序 Juval Lowy 下载代码示例 自首次发布以来,Windows Communication Foundation (WCF) 开发人员便必须处理数据协定继承方 ...

  2. WCF数据契约代理和已知类型的使用

    using Bll; using System; using System.CodeDom; using System.Collections.Generic; using System.Collec ...

  3. WCF技术剖析之十三:序列化过程中的已知类型(Known Type)

    原文:WCF技术剖析之十三:序列化过程中的已知类型(Known Type) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话) ...

  4. C# 序列化过程中的已知类型(Known Type)

    WCF下的序列化与反序列化解决的是数据在两种状态之间的相互转化:托管类型对象和XML.由于类型定义了对象的数据结构,所以无论对于序列化还是反序列化,都必须事先确定对象的类型.如果被序列化对象或者被反序 ...

  5. WCF 之 已知类型(KnownType)

    已知类型(Known types)允许在服务契约中使用多态的行为,在服务操作中暴露基本类型.将已知类型(known types)相关到基本类型(基类类型)自身;特定操作;整个服务契约采用属性声明或者配 ...

  6. 重温WCF之数据契约和序列化(四)

    一.数据契约 1.使用数据协定可以灵活控制哪些成员应该被客户端识别. [DataContract] public class Employee { [DataMember] public string ...

  7. WCF之数据契约

    从抽象层面看,WCF能够托管CLR类型(接口和类)并将它们公开为服务,也能够以本地CLR接口和类的方式使用服务.然而,CLR类型却属于.NET的特定技术.由于面向服务的一个核心原则就是在跨越服务边界时 ...

  8. java基础 File与递归练习 使用文件过滤器筛选将指定文件夹下的小于200K的小文件获取并打印按层次打印(包括所有子文件夹的文件) 多层文件夹情况统计文件和文件夹的数量 统计已知类型的数量 未知类型的数量

    package com.swift.kuozhan; import java.io.File; import java.io.FileFilter; /*使用文件过滤器筛选将指定文件夹下的小于200K ...

  9. js中Json字符串如何转成Json对象(4种转换方式)

    js中Json字符串如何转成Json对象(4种转换方式) 一.总结 一句话总结:原生方法(就是浏览器默认支持的方法) 浏览器支持的转换方式(Firefox,chrome,opera,safari,ie ...

随机推荐

  1. gluoncv voc_detection

    https://github.com/zhreshold/gluon-cv/commit/73b3986aaa2e0d0e6f3f428c12072e3a9d29905e gluoncv可能版本还没更 ...

  2. POJ2724 Purifying Machine

    嘟嘟嘟 扒下来的题意:迈克有一台可以净化奶酪的机器,用二进制表示净化的奶酪的编号.但是,在某些二进制串中可能包含有\(*\).例如\(01*100\),\(*\)其实就代表可以取\(0\),\(1\) ...

  3. yii2.0 rules 规则中场景验证字段

    除了app场景以外的其他场景都验证uid字段['uid', 'required','except'=>'app', 'message' => '参数错误'], 只有app场景验证uid字段 ...

  4. Hadoop学习之路(十八)MapReduce框架Combiner分区

    对combiner的理解 combiner其实属于优化方案,由于带宽限制,应该尽量map和reduce之间的数据传输数量.它在Map端把同一个key的键值对合并在一起并计算,计算规则与reduce一致 ...

  5. Odoo中要根据某字段值作为条件判断值,但又不想在界面显示

    在视图标签中包含这个field(包含这个字段才可以使用该字段),但其invisible属性设置为1,即:该字段不可见. <field name="字段" invisible= ...

  6. HDU 3790(两种权值的迪杰斯特拉算法)

    传送门: http://acm.hdu.edu.cn/showproblem.php?pid=3790 最短路径问题 Time Limit: 2000/1000 MS (Java/Others)    ...

  7. C编程规范, 演示样例代码。

    /*************************************************************** *Copyright (c) 2014,TianYuan *All r ...

  8. 双硬盘双系统win10+manjaro-kde搭建

    电脑sdd+hdd双硬盘,默认win10装在了sdd分区,uefi+gpt引导.现在想要在hdd中划分出一个分区安装manjaro,并在开机多重引导. 1. 制作安装盘 先去下载最新的镜像,最好在国内 ...

  9. jsp小基础归纳

    JSP的本质就是一个Servlet,JSP的运行之前会先被Tomcat服务器翻译为.java文件,然后在将.java文本编译为.class文件,而我们在访问jsp时,处理请求的就是那个翻译后的类. 1 ...

  10. linux的用户管理相关配置文件

    Linux的管理命令的本质不过是对配置文件/etc相关文件的修改罢了