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. TensorFlow函数(四)tf.trainable_variable() 和 tf.all_variable()

    tf.trainable_variable() 此函数返回的是需要训练的变量列表 tf.all_variable() 此函数返回的是所有变量列表 v = tf.Variable(tf.constant ...

  2. 4.12 Spark环境更新

    addJar方法是做什么的呢?它用于将Jar文件添加到Driver的RPC环境中. 通过addJar和addFile可以将各种任务执行所依赖的文件添加到Driver的RPC环境中, •小结 伴生对象是 ...

  3. .net core RabbitMQ 消息队列

    上篇我们说到erlang的安装,现在有了基础前提,就可以继续安装RabbitMQ了! 这里我选用的RabbitMQ版本是: PS:这个RabbitMQ版本是要对应前面erlang版本,所以前面我们安装 ...

  4. 三维偏序 cdq

    luogu_3810 就是将逆序对转化到了三维上去 原理等我寒假再补 第一维sort解决 第二维并归排序(cdq)解决 第三维树状数组 // luogu-judger-enable-o2 #inclu ...

  5. HDU 1142 A Walk Through the Forest(最短路+记忆化搜索)

    A Walk Through the Forest Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Jav ...

  6. 指纹协查统计sql

     select dic.name, NVL(zc.zc_djzs,0),NVL(zc.zc_shzs,0),NVL(zc.zc_bzzs,0), NVL(zt.zt_djzs,0),NVL(zt.zt ...

  7. 理解numpy dot函数

    python代码 x = np.array([[1,3],[1,4]]) y = np.array([[2,2],[3,1]]) print np.dot(x,y) 结果 [[11 5] [14 6] ...

  8. php多进程编程实现与优化

    PHP多进程API 创建子进程 @params void @returns int int pcntl_fork(void) 成功时,在父进程执行线程内返回产生的子进程PID,在子进程执行线程内返回0 ...

  9. EF Core 2.1 支持数据库一对一关系

    在使用EF Core和设计数据库的时候,通常一对多.多对多关系使用得比较多,但是一对一关系使用得就比较少了.最近我发现实际上EF Core很好地支持了数据库的一对一关系. 数据库 我们先来看看SQL ...

  10. 面试官问你JS基本类型时他想知道什么?

    面试的时候我们经常会被问答js的数据类型.大部分情况我们会这样回答包括:1.基本类型(值类型或者原始类型): Number.Boolean.String.NULL.Undefined以及ES6的Sym ...