再说WCF Data Contract KnownTypeAttribute

 WCF 中的序列化是用DataContractSerializer,所有被[DataContract]和[DataMemeber]标记的类和属性会被DataContractSerializer序列化。在WCF中使用Contract模式来分辨和指定序列化/反序列化的类型,它是通过http://xmlns/Class这样的命名空间来标识这个序列化的对象的,一旦在序列化过程中无法找到这样的标识(比如某个字段,或者子对象)时,序列化就会失败。KnownTypeAttribute就提供了为我们通知序列化器去寻找未知对象的映射的途径。在Remoting中这样的问题不会存在,因为Remoting实际上是通过将一个类型传递给双方来进行类型匹配的。 

         那么KnowTypeAttribute到底用在什么地方呢?上边说了,当前类的未知类型。那什么又是当前类的未知类型呢?或许说未知类型有些不恰当,但下边的实际应用可能会让你更清楚这到底是指什么。

1). 序列化对象是从期望返回的类型继承;

2). 无法确定当前所使用类型的。例如Object类型,或者接口类型,你需要告诉序列化器去寻找确切的类来进行序列化。

3). 使用泛型类型作为期望返回类型的;

4). 使用像ArrayList等以object为基础类型存储对象的; 

          下边我们以第一种类型为例说明KnownTypeAttribute的用法。序列化对象一般是参与到在服务端和客户端传递的数据。在面向对象的设计中,继承可以很好的解决很多业务问题,并简化处理。而在下边的例子中我们可以看出KnownType到底能够做什么。

namespace WcfServiceDemo

{

    [DataContract]

    public class Address

    {

        public Address()

        {

             ……

        }

 

        [DataMember]

        public string AddressCategory { get; set; }

 

        [DataMember]

        public string AddressTitle { get; set; }

 

        [DataMember]

        public string AddressDetail { get; set; }

    }

 

    [DataContract]

    public class BusinessAddress : Address

    {

        ……

    }

 

    [DataContract]

    public class HomeAddress : Address

    {

        ……

    }

}

 

public class Service1 : IService1

{

    public Address GetAddress(bool isHome)

    {

        if (isHome)

            return new HomeAddress();

        else

            return new BusinessAddress();

    }

}

 

         上边的代码中简单的生命了三个数据契约类型,Address作为基类,HomeAddress和BusinessAddress继承于Address类。在Service实现中,简单的通过一个参数来判断到底返回哪个子类。我们可以简单的写个客户端来调用一下这个服务,但很快你会发现浏览器(客户端)返回给你了错误:

Server Error in '/' Application.


The underlying connection was closed: The connection was closed unexpectedly.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Net.WebException: The underlying connection was closed: The connection was closed unexpectedly.

 

        很显然,这个错误并不能清楚的反应具体发生了什么,如果你跟进服务你会发现,所有的操作都正常,只是在返回数据的时候发生了错误。如果你愿意,你可以用DataContractSerializer类的一些方法来将一个HomeAddress序列化并反序列化为一个Address类型,你就会看到这个过程中发生了错误,序列化都无法进行。为什么呢?原因是HomeAddress/BusinessAddress的类型标识(如http://www.demo.com/BusinessAddress)无法序列化Address类型时匹配,它就不知道该把它序列化成哪个确切的类型。 

        解决方法,给Address添加KnownTypeAttribute标识,当一个HomeAddress对象或者BusinessAddress对象被传递到Address进行序列化时,序列化器认识这个对象并能根据契约来进行序列化。

[DataContract]

[KnownType(typeof(BusinessAddress))]

[KnownType(typeof(HomeAddress))]

public class Address

{

      ……

}

 

    再次调用客户端(注意:如果你是通过Service Reference来引用服务的,那你必须在编译完服务端后选择Update Service Reference来更新服务引用,否则你的变化不会反应到客户端调用),现在你应该可以看到结果了。对于KnownTypeAttribute它还有一个可以替换的选择ServiceKnownTypeAttribute,你可以将它应用到一个Service或者一个Operation(他们的区别是:当把ServiceKnownType标记给以个Service,那么在这个Service内KnownType都发生作用;而对于Operation则只在这个Operation时有效,即作用域不同。)。以下代码同样解决了上述问题:

[OperationContract]

[ServiceKnownType(typeof(BusinessAddress))]

[ServiceKnownType(typeof(HomeAddress))]

Address GetAddress(bool isHome);

 

    KnownType的另外一种标识方式是不用加代码的,在配置文件中通过声明型编程实现:

<system.runtime.serialization>

  <dataContractSerializer>

    <declaredTypes>

      <add type="WcfServiceDemo.Address, MyAssembly, Version=2.0.0.0, Culture=neutral,PublicKeyToken=null, processorArchitecture=MSIL">

        <knownType type="MyCompany.Library.Circle, MyAssembly, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null, processorArchitecture=MSIL"/>

      </add>

    </declaredTypes>

  </dataContractSerializer>

</system.runtime.serialization>

 

    而对于泛型来说,KnownType是不能被直接应用的,如果你写成[KnownType(typeof(BusinessAddress<>))]这样是不允许,但CLR给我们提供了另外一种方法来实现对序列化的通知:

[KnownType("GetKnownTypes")]

public class Address<T>

{       

    static Type[] GetKnownTypes()

    {

        return new Type[] { typeof(HomeAddress<T>) ,typeof(BusinessAddress)};

    }

}

    我们指定寻找KnownType时到GetKnownTypes方法去找,GetKnownTypes方法返回一个告知序列化器映射类型的数组。既然我们可以用方法,那是否意味着我们也可以动态的来定义GetKnownTypes返回的类型集合呢?当然,在上边的例子中你可以通过扩展GetKnownTypes方法来实现。但为了DataContract类型定义的简约和独立性,我们不妨将这个函数摘出来,或许更有利于程序结构:

[ServiceContract]

[ServiceKnownType("GetKnownTypes", typeof(KnownTypesProvider))]   

public interface IService1

{

    ……

}

 

static class KnownTypesProvider

{

    static Type[] GetKnownTypes(ICustomAttributeProvider knownTypeAttributeTarget)

    {

        Type contractType = (Type)knownTypeAttributeTarget;

        return contractType.GetGenericArguments() ;

    }

}

 

    我们将类型通知提供者定义到函数外部,并通过利用ServiceKnownType的重载构造函数传入需要去寻找的通知类提供者及其方法。这样你很容易扩展这个函数并动态加载通知类型。

         你仍然可以通过使用配置文件的方式来达到同样的功能:

  <system.runtime.serialization>

    <dataContractSerializer>

      <declaredTypes>

        <add type="MyCompany.Library.Shape,

              MyAssembly, Version=2.0.0.0, Culture=neutral,

              PublicKeyToken=XXXXXX, processorArchitecture=MSIL">

          <knownType type="MyCompany.Library.Circle,

                       MyAssembly, Version=2.0.0.0, Culture=neutral,

                       PublicKeyToken=XXXXXX, processorArchitecture=MSIL">

            <parameter type="System.Collections.Generic.Dictionary">

              <parameter type="System.String"/>

              <parameter index="0"/>

            </parameter>

          </knownType>

        </add>

      </declaredTypes>

    </dataContractSerializer>

  </system.runtime.serialization>

 

    以上代码就指定了将Circle<Dictionary<string, T>>作为Shape<T>的一个knownType。注意,当你指定某个knownType可能用到多于一个参数为泛型对象的参数时,通过index来指定与期望类型T不同的另外一个类型。例如上边的代码中指定了第一个参数为String类型(通过index指定),第二个参数T与Shape<T>的T相同,不用特别指定。

转载于:https://www.cnblogs.com/sjqq/p/6782538.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/401063.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pyinotify结合ftplib自动上传新建的文件

应用场景&#xff1a;从国内往国外上传&#xff0c;因国际带宽影响&#xff0c;速度很慢&#xff0c;于是做了一个中转FTP&#xff0c;而自动上传需求也就诞生了。代码地址&#xff1a;https://github.com/coocla/linux/blob/master/ftp/autoupload_ftp.py sftp类型&#xff1…

EFCore 的 DbFirst 模式

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

PHP读取sphinx实例

阅读原文&#xff1a;http://yzswyl.cn/blread-1611.html 1.未采用mysql二进制网络协议的代码&#xff1a; //检查sphinx是否能连接&#xff0c;不能重试两次&#xff0c;能则连接,不用mysql协议,仅供参考 function checkSphinxNoMysql() {$flag true;$retries 0;while ( $fl…

linux使用flock解决crontab任务冲突

Linux的crontab最小的间隔是每分钟执行一次&#xff0c;但是如果在这一分钟之内&#xff0c;之前的命令并没有执行完成呢&#xff1f;这样就会产生冲突。接下来我介绍一个解决冲突的办法&#xff0c;那就是linux的flock文件锁. 格式&#xff1a; flock [-sxun][-w #] fd# flock…

golang bufio解析

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

TAppEncoder的main函数

TAppEncoder是编码器工程&#xff0c;完成视频序列的编码。 运行时&#xff0c;首先调用encmain.cpp中的main函数 main函数中完成的工作主要有初始化encoder类&#xff0c;解析cfg文件&#xff0c;然后调用TAppEncTop::encode函数进入下一层&#xff0c;并且对编码过程进行计时…

【mq】从零开始实现 mq-01-生产者、消费者启动

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

远程连接Ubuntu桌面配置

1、打开终端&#xff1a;依次安装 sudo apt-get install xrdpsudo apt-get install vnc4server tightvncserversudo apt-get install xubuntu-desktop 2、安装完&#xff1a;xubuntu-desktop之后&#xff0c;做如下配置以及启动 roothd-slave2:jvm# echo "xfce4-session&q…

【大话云原生】微服务篇-五星级酒店的服务方式

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

从C#到TypeScript - Generator

从C#到TypeScript - Generator 上篇讲了Promise&#xff0c;Promise的执行需要不停的调用then&#xff0c;虽然比callback要好些&#xff0c;但也显得累赘。所以ES6里添加了Generator来做流程控制&#xff0c;可以更直观的执行Promise&#xff0c;但终级方案还是ES7议案中的asy…

C#中检查null的语法糖

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

iOS UItextView监听输入特定字符跳转页面选择选项返回

今天有朋友问我一个需求的实现,于是自己写了一个Demo简单的实现了一下: 需求是: 1>比如: 检测用户输入"A"字符串,跳转页面选择选项,将选择的选项放置textView里,作为当前的输入; 2>不是"A"字符,则正常的textView输入; 3.用户跳转选择了,则将选择的输…

PDCA循环——快速提升软件质量的必备工具

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

oracle 表空间 用户

-- create user mapecun identified by "accp"; --alter user 用户名 quota unlimited on 表空间; --alter user mapecun quota unlimited on USERS; --grant create sequence to mapecun; /** grant create session to mapecun; grant create table to mapecun; g…

如何在Web前端实现CAD图文字全文搜索功能之技术分享

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

基于Java (spring-boot)的仓库管理系统

一、项目介绍 本系统的使用者一共有系统管理员、仓库管理员和普通用户这3种角色: 1.系统管理员&#xff1a;通过登录系统后&#xff0c;可以进行管理员和用户信息的管理、仓库和物品分类的管理&#xff0c;以及操作日志的查询&#xff0c;具有全面的系统管理权限。 2.仓库管理…

基于语义感知SBST的API场景测试智能生成

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

【KMP模板】简单写个KMP~

本来easy的KMP 却一直过不了洛谷的模板题。。。 仔细一看原来在输出next数组时打的回车而不是空格。。。 身败名裂。。。 话说有个sunday貌似一般状况下比KMP快呢。。。去看看2333 #include<cstdio> #include<iostream> #include<cstring> #include<algor…

2015 CALLED THE INTERFACE OF 2014

Writer&#xff1a;BYSocket&#xff08;泥沙砖瓦浆木匠&#xff09; 微博&#xff1a;BYSocket豆瓣&#xff1a;BYSocketReprint it anywhere u want. ”Hi , Happy New Year.Written in Stupid Enlish,Dont push me *.* ” 2014 System 2015 is coming.But 2014 is not over.…

论文解读(MERIT)《Multi-Scale Contrastive Siamese Networks for Self-Supervised Graph Representation Learni

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…