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. 2、Android-UI(RecyclerView)

    2.6.滚动控件-RecylerView ListView虽然使用的效果很好但是也是有缺点的 不使用一些技巧来提升它的运行效率,性能就非常差 扩展性也不是很好 只能实现数据的纵向滚动效果 实现横向滚动 ...

  2. 4、Dubbo-工程实践

    4.实践测试 4.1).提出需求 某个电商系统,订单服务需要调用用户服务获取某个用户的所有地址: 我们现在 需要创建两个服务模块进行测试  测试预期结果: 订单服务web模块在A服务器,用户服务模块在 ...

  3. HTML5本地存储(Local Storage) 的前世今生

    长久以来本地存储能力一直是桌面应用区别于Web应用的一个主要优势.对于桌面应用(或者原生应用),操作系统一般都提供了一个抽象层用来帮助应用程序保存其本地数据 例如(用户配置信息或者运行时状态等). 常 ...

  4. Kali-linux无线网络嗅探工具Kismet

    如果要进行无线网络渗透测试,则必须先扫描所有有效的无线接入点.刚好在Kali Linux中,提供了一款嗅探无线网络工具Kismet.使用该工具可以测量周围的无线信号,并查看所有可用的无线接入点.本节将 ...

  5. 为什么要使用GetSafeHwnd()函数

    当我们想得到一个窗口对象(CWnd的派生对象)指针的句柄(HWND)时,最安全的方法是使用GetSafeHwnd()函数,通过下面的例子来看其理由: CWnd *pwnd = FindWindow(“ ...

  6. ubuntu查询命令行安装的软件的安装路径

    which git // 查询git的安装路径

  7. linux 下线程错误查找,与线程分析命令

    一. 使用top和jstack查找线程错误 我们使用jdk自带的jstack来分析.当linux出现cpu被java程序消耗过高时,以下过程说不定可以帮上你的忙: 1.top查找出哪个进程消耗的cpu ...

  8. .NET Core中NETSDK1061错误解决(转载)

    NETSDK1061错误解决 在vs生成和运行都正常,发布的时候报错 .netcore控制台项目引用另一个类库 错误信息 NETSDK1061: 项目是使用 Microsoft.NETCore.App ...

  9. sharepoint搜索配置问题

    配置sharepoint 爬网内容源,如我们有4台前端服务器,集群域名为eds.jd.com,2台用于爬网前端服务器,集群域名为crawl.eds.jd.com 配置内容源的时候,将地址配为: 结果一 ...

  10. 一次“Error Domain=AVFoundationErrorDomain Code=-11841”的调试

    一次"Error Domain=AVFoundationErrorDomain Code=-11841"的调试 起因 最近在重构视频输出模块的时候,调试碰到AVAssetReade ...