zoukankan      html  css  js  c++  java
  • 年前辞职-WCF入门(6)

     前言

    昨天早上去医院做入职体检,被告知要预约,本以为是要排队,我连视频都准备好了。。。结果就回来了。下午去了新公司那边找房子,2了,因为公司提供了班车列表,我既然就只在班车所经过的几个地方找,却遗漏了公司附近这个重要的地址。最后找了一个“江景房”,上阳台就能看到钱塘江。价格和现在的比翻了一倍,累了,不想找了。

    有朋友让我把标题前缀“年前辞职”4个字拿了,好吧,我承认,我就是靠这个吸引一部分眼球的。

    第六集 WCF DataContract & DataMember (WCF的Data和DataMember)

    这些天写下来关于那个mex还是有点困惑,早上在stackoverflow上搜到一个回答,感觉写得挺好的,在此拿出来分享一下。地址:http://stackoverflow.com/questions/21522493/what-was-the-difference-between-wsdl-mex-endpoint-in-wcf 。或许如果你有WebService的经验,理解起来会更轻松一些。站在使用者的角度,我试着拿掉了endpoint有关mex的定义,以及注释了behaviors节点,然后访问http://localhost:8080/ 页面给了我这么一个提示:

    还是回到了最初。

    还有一点,stackoverflow回答中向我们传递了一个意思,关于WCF,就像他这么用就行,因为,WCF本身还有更多的复杂有趣的东西等我们去开发实践。

    今天讲第六集,这两个是用来修饰需要序列化的实体类的特性,并且也会涉及到KnownType 看了之后觉得是一个很有用的特性。

    首先,我们来实现一个EmployeeService,主要的作用是用来根据id查询Employee,以及向数据库插入Employee。下面开始介绍:

    数据库部分

    我们新建了一张表,叫Employee,左边是表结构,右边是内容,Id列没有用自增。

    然后新建了2个存储过程,一个spGetEmployeeById,一个SaveEmployee

    select * from Employee where Id= @id;
    insert into Employee (Id ,Name,Gender,DateOfBirth) values (@id ,@name,@gender,@dateOfBirth)

    其他定义部分的就写出来了。

    服务部分 

     1     public class Employee
     2     {
     3         private int _id;
     4         private string _name;
     5         private bool _gender;
     6         private DateTime _dateOfBirth;
     7 
     8         public int Id
     9         {
    10             get { return _id; }
    11             set { this._id = value; }
    12         }
    13         public String Name
    14         {
    15             get { return _name; }
    16             set { this._name = value; }
    17         }
    18         public bool Gender
    19         {
    20             get { return _gender; }
    21             set { this._gender = value; }
    22         }
    23         public DateTime DateOfBirth
    24         {
    25             get { return _dateOfBirth; }
    26             set { this._dateOfBirth = value; }
    27         }
    28     }
    View Code

    上面是Employee 类的定义,有人可能会纳闷,为什么要额外定义个私有变量,C#这个人性化的语言不是只要写get;set就ok?开始我也有这个样的疑惑。但其实,这里是为了说明问题,特地这么写的。

    public class EmployeeService : IEmployeeService
        {
            public Employee GetEmployee(int id)
            {
                Employee emp = null;
                var connStr = ConfigurationManager.ConnectionStrings["WCFEmployee"].ConnectionString;
                using(var conn = new SqlConnection(connStr)) {
                    conn.Open();
                    var cmd = conn.CreateCommand();
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                    cmd.CommandText = "spGetEmployeeById";
                    cmd.Parameters.Add(new SqlParameter("id", id));
                    var reader = cmd.ExecuteReader();
                    if(!reader.HasRows) return emp;
                    emp = new Employee();
                    while(reader.Read()) {
                        emp.Id = Convert.ToInt32(reader["Id"]);
                        emp.Name = reader["Name"].ToString();
                        emp.Gender = Convert.ToBoolean(reader["Gender"]);
                        emp.DateOfBirth = Convert.ToDateTime(reader["DateOfBirth"]);
                    }
                }
                return emp;
            }
    
            public void SaveEmployee(Employee emp)
            {
                var connStr = ConfigurationManager.ConnectionStrings["WCFEmployee"].ConnectionString;
                using(var conn = new SqlConnection(connStr)) {
                    conn.Open();
                    var cmd = conn.CreateCommand();
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;
                    cmd.CommandText = "spSaveEmployee";
                    cmd.Parameters.Add(new SqlParameter("id", emp.Id));
                    cmd.Parameters.Add(new SqlParameter("name", emp.Name));
                    cmd.Parameters.Add(new SqlParameter("gender", emp.Gender));
                    cmd.Parameters.Add(new SqlParameter("dateOfBirth", emp.DateOfBirth));
                    cmd.ExecuteNonQuery();
                }
            }
        }
    View Code

    上面是EmployeeService.cs 用了最基本的ADO.net操作。

    再建一个控制台程序,来托管这个服务,运行成功。

    客户端调用

    新建一个WebForm的客户端,实现如下效果,代码不贴了,都很基本。

    在id框里面输入id,查询这个id的对应的信息。

    没有查到给提示。

    输入信息点保存提示,保存到数据库。

    写完之后,一切运行顺利。在介绍下面东西之前,我们先介绍几个概念

    • 什么是Serialization和Deserialization

    从WCF角度来说,Serialization(序列化)是个转换的过程,它把一个实体类转换为XML,反过来讲,通过XML文件,得到一个实体类的过程叫Deserialization(反序列化)。

    • 序列化有什么用

    这里有一篇 stackoverflow 上的问答,大致意思是说用来存储以及传输数据用的。and 序列化是必须的

    如果不特殊指定,WCF用DataContractSerializer来序列化object(终于出现标题上的关键字了)。

    为了序列化Employee,我们可以用SerializableAttribute 或者 DataContractAttribute特性修饰这个类。但看看上面的Employee类,我们并没有加上那两个特性。那是因为,从framework 3.5开始,如果我们没有使用DataContract 或者DataMember 特性,那么WCF的DataContractSerializer会自动把所有的public属性按照字典序的顺序序列化。让我们访问http://localhost:8080/?wsdl 来看看:

    搜索datacontract 

     然后在地址栏里面输入后面的schemaLocation的值 http://localhost:8080/?xsd=xsd2 回车:

    Employee是一个complexType,下面的sequence里面有他的四个属性。这是默认生成的schema。

    上面说了我们可以通过给一个类加Serializable或者是DataContract特性来显式标记一个需要序列化的类,下面我们来看看这两种方式有什么不同。

    先看用Serializable标记的:

    我们看到,所有带下划线的私有变量都被序列化了。

    再看看用DataContract的效果:

    由于我们只给类标记了DataContract特性,没有任何字段被序列化了。。。(因为没有序列化字段,客户端在调用这个类的时候也是无法获取到对应的属性的。如图:

    其实,DataContract应该是和DataMember配合使用。并且,这也是WCF推荐的做法。下面我们来实现一个。

    在此之前,我们先看一下DataMember特性所包含的属性:链接

    通过这些属性,我们可以自由的控制他们在序列化时的名称,顺序等等。

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Runtime.Serialization;
     5 using System.Text;
     6 
     7 namespace EmployeeService
     8 {
     9     [DataContract]
    10     public class Employee
    11     {
    12         private int _id;
    13         private string _name;
    14         private bool _gender;
    15         private DateTime _dateOfBirth;
    16 
    17         [DataMember(Order = 1)]
    18         public int Id
    19         {
    20             get { return _id; }
    21             set { this._id = value; }
    22         }
    23         [DataMember(Order = 2)]
    24         public String Name
    25         {
    26             get { return _name; }
    27             set { this._name = value; }
    28         }
    29         [DataMember(Order = 3)]
    30         public bool Gender
    31         {
    32             get { return _gender; }
    33             set { this._gender = value; }
    34         }
    35         [DataMember(Order = 4)]
    36         public DateTime DateOfBirth
    37         {
    38             get { return _dateOfBirth; }
    39             set { this._dateOfBirth = value; }
    40         }
    41     }
    42 }
    View Code

    通过添加DataMember特性,字段回来了,并且序列化的顺序也按照我的赋予的排好了。

    总结一下,用DataContract 和 DataMember来控制我们需要序列化的对象。

    下面还有KnowTypeAttribute的知识点,貌似有不少东西好写,还是另开一篇吧。。。文章长了看的人就更少了。。。

    Thank you!

  • 相关阅读:
    React Native 开发环境安装和配置使用报错: -bash: react-native: command not found
    ios开发不能不知的动态修复bug补丁第三方库JSPatch 使用学习:JSPatch导入、和使用、.js文件传输加解密
    ios开发视频播放后台下载功能实现 :1,ios播放视频 ,包含基于AVPlayer播放器,2,实现下载,iOS后台下载(多任务同时下载,单任务下载,下载进度,下载百分比,文件大小,下载状态)(真机调试功能正常)
    ios开发总结:Utils常用方法等收集,添加扩展类,工具类方法,拥有很多方便快捷功能(不断更新中。。。)
    alloc init初始化后对象依然还在父视图
    第二篇:_UICascadingTextStorage attributesAtIndex:effectiveRange:]: Range or index out of bounds
    Linux运维入门到高级全套常用要点
    高级Linux SA需要会做的事情
    squid源码安装下的conf文件默认值和提示
    将博客搬至CSDN
  • 原文地址:https://www.cnblogs.com/sheldon-lou/p/4220019.html
Copyright © 2011-2022 走看看