我们继续,上一回我们了解了数据协定的一部分内容,今天我们接着来做实验。好的,实验之前先说一句:实验有风险,写代码须谨慎。

实验开始!现在,我们定义两个带数据协定的类——Student和AddrInfo。

    [DataContract]
public class Student
{
[DataMember]
public string Name;
[DataMember]
public string Phone;
[DataMember]
public AddrInfo Address;
}
    [DataContract]
public class AddrInfo
{
[DataMember]
public string Province;
[DataMember]
public string City;
[DataMember]
public string DetailAddr;
}

这两个类有一个特征,Student类的Address字段是一个AddrInfo对象,而我们的服务定义如下:

    [ServiceContract(Namespace = "MyNamespace")]
public interface IService
{
[OperationContract]
Student GetStudentInfo();
}
    public class MyService : IService
{
public Student GetStudentInfo()
{
Student stu = new Student();
AddrInfo info = new AddrInfo();
info.Province = "广东省";
info.City = "佛山市";
info.DetailAddr = "火星路-300号";
stu.Name = "小陈";
stu.Phone = "1388888888";
stu.Address = info;
return stu;
}
}

方法返回的Student对象,那么,我们来测试一下,AddrInfo能不能被成功序列化和反序列化。下面是注册和启动服务的代码:

        static void Main(string[] args)
{
// 服务器基址
Uri baseAddress = new Uri("http://localhost:1378/services");
// 声明服务器主机
using (ServiceHost host = new ServiceHost(typeof(MyService), baseAddress))
{
// 添加绑定和终结点
WSHttpBinding binding = new WSHttpBinding();
host.AddServiceEndpoint(typeof(IService), binding, "/test");
// 添加服务描述
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
try
{
// 打开服务
host.Open();
Console.WriteLine("服务已启动。");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadKey();
}
}

在客户端生成的代码中,两个类都可以正确生成。

客户端测试代码如下:

        static void Main(string[] args)
{
WS.ServiceClient cli = new WS.ServiceClient();
WS.Student stu = cli.GetStudentInfo();
string msg = "学生姓名:{0}\n联系电话:{1}\n" +
"地址信息:-----------\n" +
"省份:{2}\n" +
"市区:{3}\n" +
"详细地址:{4}";
Console.WriteLine(msg, stu.Name, stu.Phone, stu.Address.Province, stu.Address.City, stu.Address.DetailAddr);
Console.ReadKey();
}

其运行结果如下:

下面我们继续实验。

每个学生可能有多个学科的成绩,因此,我们为学生类再添加一个成绩属性。

    [DataContract]
public class Student
{
[DataMember]
public string Name;
[DataMember]
public string Phone;
[DataMember]
public AddrInfo Address;
[DataMember]
public object Scores;
}
    public class MyService : IService
{
public Student GetStudentInfo()
{
Student stu = new Student();
AddrInfo info = new AddrInfo();
info.Province = "广东省";
info.City = "佛山市";
info.DetailAddr = "火星路-300号";
stu.Name = "小陈";
stu.Phone = "1388888888";
stu.Address = info;
Dictionary<string, float> m_scores = new Dictionary<string, float>();
m_scores.Add("语文", 97f);
m_scores.Add("英语", 64.5f);
m_scores.Add("数学", 38f);
m_scores.Add("历史", 77.6f);
m_scores.Add("地理", 82.3f);
stu.Scores = m_scores;
return stu;
}
}

客户端测试代码改为:

        static void Main(string[] args)
{
WS.ServiceClient cli = new WS.ServiceClient();
WS.Student stu = cli.GetStudentInfo();
string msg = "学生姓名:{0}\n联系电话:{1}\n" +
"地址信息:-----------\n" +
"省份:{2}\n" +
"市区:{3}\n" +
"详细地址:{4}";
Console.WriteLine(msg, stu.Name, stu.Phone, stu.Address.Province, stu.Address.City, stu.Address.DetailAddr);
Console.WriteLine("---------------------------------------");
Console.WriteLine("学生成绩单:");
Dictionary<string, float> scores = stu.Scores as Dictionary<string, float>;
foreach (var item in scores)
{
Console.Write("{0}:{1}\n", item.Key, item.Value);
} Console.ReadKey();
}

现在来测试,就会发生异常,因为我们为Student类加的成绩属性是object类型,而我们在协定方法中给它赋的是 Dictionary<string, float>类型,这样一来,就算可以序列化也不能被反序列化,因为Dictionary<string, float>无法识别。

现在,我们再为Student类添加一个KnownType特性,看它能不能识别。

[DataContract]
[KnownType(typeof(Dictionary<string, float>))]
public class Student
{
。。。。。
}

这时候,再运行一下。

很可惜,还是报错了,

怎么办呢?不要放弃,我们继续把学生类修改一下。

    [DataContract]
[KnownType("GetKnowTypes")]
public class Student
{
[DataMember]
public string Name;
[DataMember]
public string Phone;
[DataMember]
public AddrInfo Address;
[DataMember]
public object Scores; static Type[] GetKnowTypes()
{
return new Type[] { typeof(Dictionary<string,float>) };
}
}

GetKnowTypes方法是静态方法,KnownType的构造函数中传递该方法的名字。看看这回调用能否成功?

坚持就是胜利,看到了吧,这回OK了!高兴吧。

这里我们可以总结一下,在一些比较复杂的类型无法反序列化(不能识别类型)的时候,就得考虑使用KnownTypeAttribute来标注可能涉及到的外部类型,但如果遇到像泛型这些较为复杂的类型,就要考虑在带数据协定的类中添加一个静态方法,该方法返回Type 的IEnumerable,一般是Type[]就可以了,而在KnownTypeAttribute的构造函数中使用这个方法的名字。

传说中的WCF(6):数据协定(b)的更多相关文章

  1. 传说中的WCF(5):数据协定(a)

    在第4篇中,咱们了解了发送/接收SOAP头,从本篇开头,我们不妨更深入地去探求一下有关WCF中的消息到底是啥玩意儿.WCF庞大而复杂,而从 MSDN文档中,你会看到许多很专业很抽象的东西,你不禁会问, ...

  2. WCF初探-16:WCF数据协定之基础知识

    数据协定概念 “数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每一个做数 ...

  3. WCF初探-17:WCF数据协定之等效性

    数据协定等效性特点概述 对于客户端要将某种类型的数据成功发送到服务,或者服务要将数据成功发送到客户端的情况,接收端上并不一定必须存在此发送数据类型. 唯一的要求是两种类型的数据协定应该等效. 要使数据 ...

  4. WCF初探-18:WCF数据协定之KnownType

    KnownTypeAttribute 类概述 在数据到达接收终结点时,WCF 运行库尝试将数据反序列化为公共语言运行库 (CLR) 类型的实例.通过首先检查传入消息选择为反序列化而实例化的类型,以确定 ...

  5. WCF学习心得------(六)数据协定

    --前言 最近各种事忙的把之前的WCF学习给耽误了一些,今天抽时间把之前的学习内容给总结了一下,因为知识点比较细碎没有做太多的练习示例,只是对其中关键的知识点做了总结,希望可以对大家有所帮助. 第六章 ...

  6. 传说中的WCF(8):玩转消息协定

    Message翻译成中文,相信各位不陌生,是啊,就是消息,在WCF中也有消息这玩意儿,不知道你怎么去理解它.反正俺的理解,就像我们互发短信一个道理,通讯的双方就是服务器与客户端,说白了吧,就是二者之间 ...

  7. WCF基础之数据协定

    数据协定最重要的当然就是DataContract和DataMember.这两个特性能应用到类.结构和枚举.这个两个特性跟服务契约的特点是一样的,只有被DataContract标记的类和类中被标记Dat ...

  8. 我们一起学习WCF 第五篇数据协定和消息协定

    A:数据协定(“数据协定”是在服务与客户端之间达成的正式协议,用于以抽象方式描述要交换的数据. 也就是说,为了进行通信,客户端和服务不必共享相同的类型,而只需共享相同的数据协定. 数据协定为每个参数或 ...

  9. 【WCF】错误协定声明

    在上一篇烂文中,老周给大伙伴们介绍了 IErrorHandler 接口的使用,今天,老周补充一个错误处理的知识点——错误协定. 错误协定与IErrorHandler接口不同,大伙伴们应该记得,上回我们 ...

随机推荐

  1. 微软云平台媒体服务实践系列 1- 使用静态封装为iOS, Android 设备实现点播(VoD)方案

    微软的云平台媒体服务为流媒体服务提供了多种选择,在使用流媒体服务为企业做流媒体方案时,首先需要确认要流媒体接收目标,如针对广大iOS, Android移动设备,由于它们都支持HLS 格式的流媒体,基于 ...

  2. Go语言工程结构

    Go是一门推崇软件工程理念的编程语言. Go的代码必须放在GOPATH目录下,它应该包含三个子目录: src:用于以代码包的形式组织并保存Go源码文件.应该分为三类:库源码文件.命令源码文件.测试源码 ...

  3. php取整函数floor(),round(),intval(),ceil()

    ceil -- 进一法取整说明float ceil ( float value )返回不小于 value 的下一个整数,value 如果有小数部分则进一位.ceil() 返回的类型仍然是 float, ...

  4. C# 生成XML 多级节点

    直接上代码: 在应用程序中 class Program { //public static JsonServiceClient Service = new JsonServiceClient(Conf ...

  5. graphicsMagick 文档

    ImageMagick资料 ---------------------------------------------------------------------------- ImageMagi ...

  6. LintCode-Serialization and Deserialization Of Binary Tree

    Design an algorithm and write code to serialize and deserialize a binary tree. Writing the tree to a ...

  7. JIRA安装过程中链接mysql的问题!

    测试下我使用的是mysql7.5的版本,JIRA是6.3.6!这是版本引起的问题! 服务器上原生的mysql驱动jar包:Mysql-connector-java-5.1.18-bin 可参考:htt ...

  8. JavaScript 关于变量作用域的一道面试题

    ShineJaie 原创,转载请注明出处. 昨晚在一个交流群里看到有位网友提了一个他的面试题求助答疑.刚好我也有看到,就对这个问题思考了一下,觉得这道题对理解 JavaScript 作用域还是很有帮助 ...

  9. curl Protocol 'http not supported or disabled in libcurl

    C:\Documents and Settings\ganiks.liu\Desktop\curl-7.37.0-win32\bin>curl -V curl 7.37.0 (i386-pc-w ...

  10. WC2016游记

    出发的时候,长沙忽然就出了太阳,明媚而和煦. [day0 25] 噫吁嚱,危乎高哉!蜀道之难,难于上青天! 总之本来上午已经准备好9:50的飞机…然后就在一次次的手机查询中变成了5点多…然后也不是直飞 ...