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

实验开始!现在,我们定义两个带数据协定的类——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. android几种定时器机制及区别

    在android中,经常用到的定时器主要有以下几种实现:一.采用Handler与线程的sleep(long )方法二.采用Handler的postDelayed(Runnable, long) 方法三 ...

  2. Go语言的类型转化

    Go语言要求不同的类型之间必须做显示的转换.转化分为类型转换和接口转化. 类型转换的思路是: X类型需要转换为Y类型,语法是T(x). 如果对于某些地方的优先级拿不准可以自己加()约束,变成(T)(X ...

  3. openSUSE install failed

    install openSUSE 13.1 with vmware play (version 6.0.0)  calling the yast module 'inst_autoinit has f ...

  4. 主要从架构上来做优化,负载均衡、CDN、静态化、数据库的水平切割和纵向切割、读写分离、分布式缓存着手

    语言知识一种工具,甚至技术本身也只是一种工具,本身并不值钱,关键在于用于何种行业,产生了什么价值. 但从语言来看,我个人更喜欢php,然后是C#,然后是java从框架而言,先是java,然后C#,再次 ...

  5. FPGA保留信号的语句

    (*synthesis,keep*) (*synthesis,probe_port,keep *) 例:(*synthesis,probe_port,keep *) wire e; 可用于wire型和 ...

  6. 微软职位内部推荐-SR DEV

    微软近期Open的职位: JD 如果你想试试这个职位,请跟我联系,我是微软的员工,可以做内部推荐.发你的中英文简历到我的邮箱:Nicholas.lu.mail(at)gmail.com

  7. mobiscroll 控件的使用(手机端日历控件)

    先上一张图吧: 控件的下载地址:http://www.kuitao8.com/20140604/2615.shtml 文档API地址:http://docs.mobiscroll.com/2-13-2 ...

  8. Kibana 修改logo及汉化导航

    修改此文件下E:\happy\kinbana\kibana-4.2.2-windows\kibana-4.2.2-windows\optimize\bundles的kibana.bundle.js文件 ...

  9. android 下载图片出现SkImageDecoder::Factory returned null,BitmapFactory.Options压缩

    网上有很多说是因为没有采用HttpClient造成的,尼玛,我改成了HttpClient 请求图片之后还是会出现SkImageDecoder::Factory returned null, 但是直接使 ...

  10. 浅谈GitHub

    Git 是一个面向开源及私有软件项目的托管平台,因为只支持Git作为唯一的版本库格式进行托管,故名GitHub. Gith是一个基于 git 的社会化代码分享社区,所谓 social coding.你 ...