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事业哦

时间: 2024-10-02 15:07:07

WCF中数据契约之已知类型的几种公开方式的相关文章

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

WCF下的序列化与反序列化解决的是数据在两种状态之间的相互转化:托管类型对象和XML.由于类型定义了对象的数据结构,所以无论对于序列化还是反序列化,都必须事先确定对象的类型.如果被序列化对象或者被反序列化生成的对象包含不可知的类型,序列化或者反序列化将会失败.为了确保DataContractSerializer的正常序列化和反序列化,我们需要将“未知”类型加入DataContractSerializer“已知”类型列表中. 一.未知类型导致序列化失败 .NET的类型可以分为两种:声明类型和真实类

WCF之数据契约

从抽象层面看,WCF能够托管CLR类型(接口和类)并将它们公开为服务,也能够以本地CLR接口和类的方式使用服务.然而,CLR类型却属于.NET的特定技术.由于面向服务的一个核心原则就是在跨越服务边界时,服务不能够暴露它们的实现技术.因此,不管客户端采用了何种技术,它都能够与服务交互.使用基于XML的样式或信息集(Infoset)实现CLR数据类型与标准的与平台无关的表示形式之间的转换.此外,服务需要一种正式的方法声明两者之间的转换,这就是契约. Serializable所指代的涵义是类型的所有成

重温WCF之数据契约(四)

1.使用数据协定可以灵活控制哪些成员应该被客户端识别. [DataContract] public class Employee { [DataMember] public string Name { get; set; } [DataMember] public int Age { get; set; } [DataMember] public string City { get; set; } } [ServiceContract] public interface IService { [

利用matlab提取并分割RGB图像中的某一个已知像素值的图像

已知一副RGB图像中的的像素值,利用matlab将其分割出来并以二进制图像形式显示: %extract.m clear all; I=imread('new_original.png'); figure,imshow(I),title('Original Image'); bw=im2bw(I,0.3); %figure,imshow(bw),title('Gray Image'); rgb=[252,2,4]; img=extract_rgb(I,rgb); figure,imshow(im2

Android中Fragment与Activity之间的交互(两种实现方式)

(未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如何创建Fragment混合布局做了详细的分析,今天就来详细说道说道Fragment与宿主Activity之间是如何实现数据交互的. 我们可以这样理解,宿主Activity中的Fragment之间要实现信息交互,就必须通过宿主Activity,Fragment之间是不可能直接实现信息交互的. Fragment与

wcf已知类型 known type

1.服务契约的定义 /* Copyright (c) 2014 HaiHui Software Co., Ltd. All rights reserved * * Create by [email protected] at 2014-10-14 10:09:00 * */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel;

matlab中怎样由上已知的三角矩阵或下三角矩阵构建对称矩阵??

方法:先将对角元素全部置为0,然后将上三角矩阵或下三角矩阵进行转置,最后进行两个矩阵相加,再填充对角元素: 1 >> a=[0,1,2;0,0,3;0,0,0]; 2 >> a 3 4 a = 5 6 0 1 2 7 0 0 3 8 0 0 0 9 >> a=a+a'; 10 >> a 11 12 a = 13 14 0 1 2 15 1 0 3 16 2 3 0

sql注入过程中后台数据库类型的三种判断方式

后台数据库类型判断: 一.通过页面返回的报错信息,一般情况下页面报错会显示是什么数据库类型,在此不多说: 二.通过各个数据库特有的数据表来判断: 1.mssql数据库 http://127.0.0.1/test.php?id=1 and (select count(*) from sysobjects)>0 and 1=1 2.access数据库 http://127.0.0.1/test.php?id=1 and (select count(*) from msysobjects)>0 an

MVC4.0中ViewBag、ViewData、TempData和ViewModel几种传值方式的区别

MVC框架实现了数据的分离,使页面看起来更加的简洁,MVC4.0中Controller和View的数据传输有上边这几种方式,今天我们来探讨下这几种方式的却别. 一:ViewBag和ViewData ViewBag和ViewData 其实是互通的,他们的区别是 ViewBag不再是键值对的存储形式,而是dynamic动态类型的,他会在程序运行的过程中被解析. 实例 ViewBag本质上是ViewData,只不过是多了层dynamic控制,所以ViewBag和ViewData只针对当前Action有