前言

又堕落了,哎。

公司是做乙方的,工资还凑合,主要是项目基本都已完成,进去就是干维护,体会不到那种从头彻尾的成就感。项目中具体用了EF+Ado.net+WCF+WPF+(VB.net啊,坑啊,完全不知道是这个东西),整个解决方案有47个项目,是一个国际化的电话保险销售系统中的一部分。感觉自己是去体验生活的。这个项目也就是自己学习WCF的原因。

工作方面,等手上的结束了再卖自己一次吧。

第十集 Message Contract in WCF (WCF 的MessageContract特性)

很简单的一集,讲的主要是WCF中的MessageContract特性,具体作用是用来控制WCF 的xml request和response的soap消息格式。可以理解为前面讲过的DataContract的升级版。如果我们想在程序上完全控制soap消息的格式,这就是一个很好的解决方案。

视频上通过修改以前的Demo来演示了一遍他的具体使用。我们也来做一遍。

首先,定义两个类EmployeeRequest 和 EmployeeInfo

     [MessageContract(IsWrapped = true, WrapperName = "EmployeeRequestObj", WrapperNamespace = "http://HelloWcf.com/2015/02/04")]
public class EmployeeRequest
{
[MessageHeader(Namespace = "http://HelloWcf.com/2015/02/04")]
public String LicenseKey { get; set; } [MessageBodyMember(Namespace = "http://HelloWcf.com/2015/02/04")]
public int Id { get; set; }
}
[MessageContract]
public class EmployeeInfo
{
public EmployeeInfo()
{ }
public EmployeeInfo(Employee emp)
{
this.ID = emp.Id; this.Name = emp.Name;
this.Gender = emp.Gender; this.DOB = emp.DateOfBirth;
this.EmployeeType = emp.EmployeeType;
}
[MessageBodyMember]
public int ID { get; set; }
[MessageBodyMember]
public String Name { get; set; }
[MessageBodyMember]
public bool Gender { get; set; }
[MessageBodyMember]
public DateTime DOB { get; set; }
[MessageBodyMember]
public EmployeeType EmployeeType { get; set; }
}

区别与以前的DataContract ,这个类是用MessageContract来修饰,里面的属性用MessageHeader 或者 MessageBodyMember ,作用很明显,分别对应soap message里面的head 和 body。

LicenseKey在实际的环境中用来标识客户端的身份,他可以以加密的方式存在,以后会讲到。放在Header中,区别于我们Request的body中具体业务逻辑相关的内容。

然后修改IEmployeeService这个 ServiceContract

     [ServiceContract]
public interface IEmployeeService
{
[OperationContract]
EmployeeInfo GetEmployee(EmployeeRequest req); [OperationContract]
void SaveEmployee(EmployeeInfo emp); }

注意,当我们修改了原先的两个OperationContract 方法的参数后,客户端就不晓得原先的Employee的概念,他们只知道现在的Request 和 Info。

接口改完之后自然要改写接口的实现

     public class EmployeeService : IEmployeeService
{
public EmployeeInfo GetEmployee(EmployeeRequest er)
{
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", er.Id));
var reader = cmd.ExecuteReader();
if(!reader.HasRows) return null;
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"]);
emp.EmployeeType = (EmployeeType)Convert.ToInt16(reader["EmployeeType"]);
}
}
return new EmployeeInfo(emp);
} public void SaveEmployee(EmployeeInfo 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.DOB));
cmd.Parameters.Add(new SqlParameter("employeeType", (short)emp.EmployeeType));
cmd.ExecuteNonQuery();
}
} }

全是基本的Ado.net的内容,可不看。测试项目用EntityFramework来做挺爽的。记得在VPN挂掉之前下了视频同个作者的EF教程,等学完这个再相对系统的学习一下EF。

服务端OK了,启动Host运行一下。(记得要以管理员方式运行host)

客户端更新一下服务引用,修改一下以前的两个click事件的代码

     protected void btnGet_Click(object sender, EventArgs e)
{
IEmployeeService client = new EmployeeServiceClient();
try {
var emp = client.GetEmployee(new EmployeeRequest() { LicenseKey = "ABCDEFGHI1234567", Id = Convert.ToInt32(tbId.Text) });
if(emp == null) { tbName.Text = ""; tbDateOfBirth.Text = ""; rbGenderList.SelectedIndex = -; throw new Exception("没有找到员工"); }
lbRstMsg.Text = "查找成功";
tbName.Text = emp.Name; tbDateOfBirth.Text = emp.DOB.ToShortDateString(); rbGenderList.SelectedValue = emp.Gender.ToString();
} catch(Exception ex) {
lbRstMsg.Text = ex.Message;
} finally {
}
}
protected void btnSave_Click(object sender, EventArgs e)
{
IEmployeeService client = new EmployeeServiceClient();
try { var emp = new EmployeeInfo()
{
ID = Convert.ToInt32(tbId.Text), Name = Convert.ToString(tbName.Text),
Gender = Convert.ToBoolean(rbGenderList.SelectedValue), DOB = Convert.ToDateTime(tbDateOfBirth.Text)
};
client.SaveEmployee(emp);
lbRstMsg.Text = "保存成功";
} catch(Exception ex) {
lbRstMsg.Text = ex.Message;
}
}

话说这个WebForm的Demo,写起来也挺开心的。

这里有个要注意的地方是第三行,实例化client的时候要定义个IEmployeeService 接口类型,不能直接用var来,如果用var就是后面的EmployeeServiceClient类型,他的参数不是ServiceContract中定义的EmployeeRequest,至于为什么,我也不晓得,以后应该会知道的吧。

最后保存,编译,测试一下。

一切如愿,再来看看上集中讲的Log。

首先是Request:

 <MessageLogTraceRecord>
<HttpRequest xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
<Method>POST</Method>
<QueryString></QueryString>
<WebHeaders>
<VsDebuggerCausalityData>uIDPo34fm0IuoetItvuIdT55jAEAAAAAXsy48FQlpECWY/zesZsAtJ94pCeN9F5IvPTu2MbWQ3AACQAA</VsDebuggerCausalityData>
<SOAPAction>"http://tempuri.org/IEmployeeService/GetEmployee"</SOAPAction>
<Connection>Keep-Alive</Connection>
<Content-Length>291</Content-Length>
<Content-Type>text/xml; charset=utf-8</Content-Type>
<Accept-Encoding>gzip, deflate</Accept-Encoding>
<Expect>100-continue</Expect>
<Host>localhost:8080</Host>
</WebHeaders>
</HttpRequest>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:LicenseKey xmlns:h="http://HelloWcf.com/2015/02/04">ABCDEFGHI1234567</h:LicenseKey>
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:8080/EmployeeService</To>
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IEmployeeService/GetEmployee</Action>
</s:Header>
<s:Body>
<EmployeeRequestObj xmlns="http://HelloWcf.com/2015/02/04">
<Id>1</Id>
</EmployeeRequestObj>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>

Header中有LicenseKey,body中有Id。

再看Response:

 <MessageLogTraceRecord>
<Addressing xmlns="http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace">
<Action>http://tempuri.org/IEmployeeService/GetEmployeeResponse</Action>
</Addressing>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<ActivityId CorrelationId="7451a535-182c-4b89-8e42-8e312b48d8e0" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">f50e4154-a211-4ed1-b959-9965f22a70d3</ActivityId>
</s:Header>
<s:Body>
<EmployeeInfo xmlns="http://tempuri.org/">
<DOB>1990-01-02T00:00:00</DOB>
<EmployeeType>FullTimeEmployee</EmployeeType>
<Gender>true</Gender>
<ID>1</ID>
<Name>员工1</Name>
</EmployeeInfo>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>

属性都是我们在EmployeeInfo中定义的,WrapperName,Namespace等也都ok。

综上所述,有了MessageContract这个特性,我们对soap信息可以想怎么干就怎么干。

ThankYou。

WCF入门(10)的更多相关文章

  1. 学习WCF入门的第一个实例

    一.概述 WCF说白了就是一个基于终结点的通信手段!就是Service端提供一定的功能实现,然后暴露出一个或多个终结点,Client端调用Service端的功能(可以理解为调用一个函数),那么Clie ...

  2. 无废话WCF入门教程六[一个简单的Demo]

    一.前言 前面的几个章节介绍了很多理论基础,如:什么是WCF.WCF中的A.B.C.WCF的传输模式.本文从零开始和大家一起写一个小的WCF应用程序Demo. 大多框架的学习都是从增.删.改.查开始来 ...

  3. WCF入门(22)

    前言 本还想写一集WCF入门教程的,心情实在不好,明天又还有面试,改天再写吧. 说一下今天遇到的入职坑.面试能坑,上班能坑,完全没想到入职也能坑.切身经历. 今年10月份想换工作,更新了一下简历,接到 ...

  4. WCF入门教程(图文)VS2012

    WCF入门教程(图文)VS2012 上一遍到现在已经有一段时间了,先向关注本文的各位“挨踢”同仁们道歉了.小生自认为一个ITer如果想要做的更好,就需要将自己的所学.所用积极分享出来,接收大家的指导和 ...

  5. WCF入门教程(四)通过Host代码方式来承载服务 一个WCF使用TCP协议进行通协的例子 jquery ajax调用WCF,采用System.ServiceModel.WebHttpBinding System.ServiceModel.WSHttpBinding协议 学习WCF笔记之二 无废话WCF入门教程一[什么是WCF]

    WCF入门教程(四)通过Host代码方式来承载服务 Posted on 2014-05-15 13:03 停留的风 阅读(7681) 评论(0) 编辑 收藏 WCF入门教程(四)通过Host代码方式来 ...

  6. 【转】WCF入门教程六[一个简单的Demo]

    一.前言 前面的几个章节介绍了很多理论基础,如:什么是WCF.WCF中的A.B.C.WCF的传输模式.本文从零开始和大家一起写一个小的WCF应用程序Demo. 大多框架的学习都是从增.删.改.查开始来 ...

  7. WCF入门教程(五)配置文件

    WCF入门教程(五)配置文件 服务协定以及实现写好后,需要将相关服务公布出去,就需要HOST来承载,供客户端来调用. 承载服务有两种方式,一种通过配置文件,一种通过代码进行配置.上一章已经介绍了代码方 ...

  8. WCF入门教程(四)通过Host代码方式来承载服务

    WCF入门教程(四)通过Host代码方式来承载服务 之前已经讲过WCF对外发布服务的具体方式. WCF入门教程(一)简介 Host承载,可以是web,也可以是控制台程序等等.比WebService有更 ...

  9. WCF入门教程(三)定义服务协定--属性标签

    WCF入门教程(三)定义服务协定--属性标签 属性标签,成为定义协议的主要方式.先将最简单的标签进行简单介绍,以了解他们的功能以及使用规则. 服务协定标识,标识哪些接口是服务协定,哪些操作时服务协定的 ...

  10. WCF入门教程(二)如何创建WCF服务

    WCF入门教程(二)从零做起-创建WCF服务 通过最基本的操作看到最简单的WCF如何实现的.这是VS的SDK默认创建的样本 1.创建WCF服务库 2.看其生成结构 1)IService1.cs(协议) ...

随机推荐

  1. docker常用术语命令

    镜像(Image) vs Dockerfile 这组概念很少会让人产生疑惑,但是这两者的区别非常重要.Docker在镜像(image)中运行你的代码,而不是Dockerfile.Dockerfile是 ...

  2. 关于 Python 你需要知道的几个概念

    Python 一种支持面向对象和函数式(面向过程)的高级编程语言 CPython 由 C 语言编译,一种默认的,通常我们所提及的基于 C 的 Python 的一种实现 Cython 一种 Python ...

  3. 三星嵌入式开发平台 三星Cortex-A9 4412 POP与SCP对比

    iTOP-4412核心板是迅为电子推出的一款高端四核核心板,其中分为POP封装与SCP封装,配备三星Exynos 4412四核处理器,主频为1.4GHz,内置16GB存储空间.该板设计小巧.配备三星自 ...

  4. Centos 6.5(64bit)上安装Vertica single node

    在Win8上使用虚拟机Virtualbox安装Centos6.5,想在上面安装vertica. 以下记录了我在安装的过程中遇到的问题与一些解决方案. 1.安装Centos的时候遇到了一个恼人的问题,即 ...

  5. 软件工程实训项目案例--Android移动应用开发

    实训过程 角色分工 1.项目经理:负责项目的组织实施,制定项目计划,并进行跟踪管理 2.开发人员:对项目经理及项目负责 3.需求分析员:负责系统的需求获取和分析,并协助设计人员进行系统设计 4.系统设 ...

  6. Codeforces Round #263 Div.1 B Appleman and Tree --树形DP【转】

    题意:给了一棵树以及每个节点的颜色,1代表黑,0代表白,求将这棵树拆成k棵树,使得每棵树恰好有一个黑色节点的方法数 解法:树形DP问题.定义: dp[u][0]表示以u为根的子树对父亲的贡献为0 dp ...

  7. UVALive 6255 Kingdoms --状态搜索

    题意:n个国家,给出国家间相互的债务关系,每个国家如果债务>收入就要破产,破产后该国的所有债务关系全部清除,第一个破产的国家不同有可能造成最后的没破产的国家的不同,问哪些国家有可能成为独自存活的 ...

  8. eclipse菜单解释及中英对照

    在使用Eclipse作为开发工具的时候,建议使用英文版本的(直接百度从官网下就行,这里不详细描述,如果有问题,咱们私聊).虽然中文版本的对于和我一样对英文是小白的看起来特别爽,但是公司大多是英文版本的 ...

  9. 获取WIN10技术预览版

    说明 这是一款预发行软件 在进行商业发行之前,我们可能会对 Windows Technical Preview 进行大量修改. Microsoft 不对此处提供的信息作任何明示或默示的担保. 有些产品 ...

  10. java 16 -3 Vector的特有功能

    /* * Vector的特有功能: * 1:添加功能 替代 * public void addElement(Object obj) -- add() * 2:获取功能 * public Object ...