Message小结(二)
当客户端调用一个WCF接口时,客户端将请求消息发送到服务端,服务端再返回回复消息。WCF内部实现了消息处理的所有细节,但是并不意味着一切不可更改。WCF也提供了一些方法让开发人员在消息发送前对消息进行修改,在收到消息后也可以获取消息主体、报头。本篇介绍一个例子来手工控制消息发送的细节。介绍之前先介绍几个类。
1.创建消息报头MessageHeader
MessageHeader没有提供public构造函数,可以通过
(1)静态方法public static MessageHeader CreateHeader(string name, string ns, object value)创造一个MessageHeader对象。value是一个可序列化的对象,默认序列化器是DataContractSerializer。
(2) MessageHeader<T>提供了一个泛型构造消息报头的方式。创建一个MessageHeader<T>对象后,通过调用GetUntypedHeader并指定名称和命名空间可以更方便的构造一个报头。
MessageHeader<myHeaderElement> header = new MessageHeader<myHeaderElement>(element);
MessageHeader head= header.GetUntypedHeader("myHeaderElement", "http://cnblogs.com/lh218")
更多用法可以参考MSDN MessageHeader<T>类 、MessageHeader类
2.获取当前即将发送的消息、收到的消息
通过服务当前上下文可以获得即将发送的消息报头集合、消息属性集合,收到的消息报头集合、消息属性集合。可以在这些集合中添加自定义消息报头,就可以人为的定制消息内容。值得一提的是消息属性只能够本地信道栈使用,客户端的消息属性无法传送到服务端。
OperationContext.Current.IncomingMessageHeaders:获取收到的消息报头
OperationContext.Current.IncomingMessageProperties:获取收到的消息属性
OperationContext.Current.OutgoingMessageHeaders:即将要发送的消息的消息报头
OperationContext.Current.OutgoingMessageProperties:即将要发送的消息的消息属性
更多信息参考OperationContext 属性
先定义一个自定义类,后续添加到消息报头中。
[DataContract]
public class myHeaderElement
{
[DataMember]
public string myAction;
}
下面是客户端代码。
(1)使用不加密的WS2007HttpBinding。
(2)向OutgoingMessageHeaders添加一个myHeaderElement报头,并指定名称和命名空间。
(3)向OutgoingMessageProperties中添加一个myHeaderElement属性。
(4)调用服务端的Add方法后立刻通过IncomingMessageHeaders获取从服务端返回的消息的消息报头。
static void Main(string[] args)
{
WS2007HttpBinding bind = new WS2007HttpBinding();
bind.Security = new WSHttpSecurity();
bind.Security.Mode = SecurityMode.None;
ICalculator client = ChannelFactory<ICalculator>.CreateChannel(bind, new EndpointAddress("http://localhost:7799"));
using (OperationContextScope scope = new OperationContextScope(client as IContextChannel))
{
myHeaderElement element = new myHeaderElement() { myAction = "Hello,I'm Client,1+2 = ?" };
//创建报头,并添加到消息报头中
MessageHeader<myHeaderElement> header = new MessageHeader<myHeaderElement>(element);
OperationContext.Current.OutgoingMessageHeaders.Add(header.GetUntypedHeader("myHeaderElement", "http://cnblogs.com/lh218")); //添加到属性
MessageProperties Properties = OperationContext.Current.OutgoingMessageProperties;
Properties.Add("myHeaderElement", element);
Console.WriteLine("属性数量:{0}",OperationContext.Current.OutgoingMessageProperties.Count);
Console.WriteLine("属性中是否包含 “OrderProperty”:{0}", OperationContext.Current.OutgoingMessageProperties.ContainsKey("myHeaderElement")); //读取属性
object ele=null;
OperationContext.Current.OutgoingMessageProperties.TryGetValue("myHeaderElement", out ele);
Console.WriteLine("属性中的myAction:{0}", ((myHeaderElement)ele).myAction); client.Add(1, 2);
myHeaderElement backElement = OperationContext.Current.IncomingMessageHeaders.GetHeader<myHeaderElement>("myHeaderElementBack", "http://cnblogs.com/lh218");
Console.WriteLine(backElement.myAction);
}
}
服务端代码:
(1)通过IncomingMessageProperties获取从客户端发送过来的属性。其实这里无法获取客户端设置的myHeaderElement属性,因为属性不是SOAP的标准内容,只在客户端内部信道栈使用。
(2)IncomingMessageHeaders获取报头内容并打印。
(3)OutgoingMessageHeaders添加一个报头内容发送给客户端。
public class Calculator : ICalculator
{
public int Add(int x, int y)
{
if (OperationContext.Current.IncomingMessageProperties != null)
{
object o=null;
OperationContext.Current.IncomingMessageProperties.TryGetValue("myHeaderElement", out o);
if (null != o && null != o as myHeaderElement)
{
myHeaderElement element1 = o as myHeaderElement;
Console.WriteLine("From Properties:{0}", element1.myAction);
}
}
Console.WriteLine("Service:");
//从报头获取myHeaderElement
myHeaderElement element2 = OperationContext.Current.IncomingMessageHeaders.GetHeader<myHeaderElement>("myHeaderElement", "http://cnblogs.com/lh218");
Console.WriteLine("From Headers:{0}", element2.myAction); //创建报头,并添加到消息报头中
element2.myAction = "From Service:1+2=3";
MessageHeader<myHeaderElement> header = new MessageHeader<myHeaderElement>(element2);
OperationContext.Current.OutgoingMessageHeaders.Add(header.GetUntypedHeader("myHeaderElementBack", "http://cnblogs.com/lh218"));
return x + y;
}
}
服务寄宿程序代码:
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(Calculator));
WS2007HttpBinding bind = new WS2007HttpBinding();
bind.Security = new WSHttpSecurity();
bind.Security.Mode = SecurityMode.None;
host.AddServiceEndpoint(typeof(ICalculator), bind, "http://localhost:7799");
host.Opened += delegate { Console.WriteLine("Service Start!"); };
host.Open();
while (true) ;
}
}
[ServiceContract]
public interface ICalculator
{
[OperationContract]
int Add(int x, int y);
}
通过TcpTrace工具拦截到的客户端发给服务端的消息:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">http://tempuri.org/ICalculator/Add</a:Action>
<myHeaderElement xmlns="http://cnblogs.com/lh218" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<myAction xmlns="http://schemas.datacontract.org/2004/07/ClassLibrary1">Hello,I'm Client,1+2 = ?</myAction>
</myHeaderElement>
<a:MessageID>urn:uuid:7d3c93ad-acc1-42d7-b198-7db118392f46</a:MessageID>
<a:ReplyTo>
<a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo>
<a:To s:mustUnderstand="1">http://localhost:7788/</a:To>
</s:Header>
<s:Body>
<Add xmlns="http://tempuri.org/">
<x>1</x>
<y>2</y>
</Add>
</s:Body>
</s:Envelope>
可以看到在Header添加了一个myHeaderElement类型的元素。
运行效果,客户端发送的消息中添加了一个myHeaderElement类型对象作为消息报头,内容为:Hello,I'm Client,1+2 = ?
服务端回复的消息中,也有一个名为myHeaderElementBack的报头。内容为:From Service:1+2=3.
意义就在于当你需要向一个WCF接口发送更多信息时,但是又不能改变接口增加参数而影响其它调用者,通过消息报头的传递方式可以达到在最小的影响范围内实现业务需求。
客户端:

服务端:

Message小结(二)的更多相关文章
- gulp使用小结(二)
接上篇文章接Gulp使用小结(一) 内容如下: 首先,偶在gulp-demos上已经提交了个较通用的栗子...俺琢磨半天,原准备分阶段搞些 Gulp 套路,但是写完介个栗子之后,觉得已经能覆盖绝大多数 ...
- Vue学习小结(二)
接上一批,小结(二). 三.导航内容(含左侧导航及顶部面包屑导航) 其实导航条主要根据element-ui的教程进行编写,官网:http://element-ui.cn/#/zh-CN/compone ...
- Message小结(一)
一.消息版本 为了区别消息的结构和寻址机制,W3C定制了SOAP1.1和SOAP1.2定义消息的结构,WS-Addressing 2004和WS-Addressing 1.0定义消息的寻址机制. ...
- python --- 字符编码学习小结(二)
距离上一篇的python --- 字符编码学习小结(一)已经过去2年了,2年的时间里,确实也遇到了各种各样的字符编码问题,也能解决,但是每次都是把所有的方法都试一遍,然后终于正常.这种方法显然是不科学 ...
- Element Vue 开箱即用框架如何使用-测试开发【提测平台】阶段小结(二)
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 上一篇总结了后端服务接口的开发,这篇我们主要来总结下前后端分离开发中的前端部分,主要是开箱即用的框架介绍和之前章节组件的梳理和部分的扩展内 ...
- jstree使用小结(二)
继续上一篇: 1.数据 按照官网的json数据返回格式: 有两种格式,我使用的格式如下: $('#jstree1').jstree({ 'core' : { 'data' : [ { "id ...
- Spring知识点小结(二)
一.配置非自定义的Bean(数据源DataSource模型) DBCP数据源: 导入dbcp的jar包:dbcp+pool+connector 代码实现: ...
- 动态规划小结 - 二维动态规划 - 时间复杂度 O(n*n)的棋盘型,题 [LeetCode] Minimum Path Sum,Unique Paths II,Edit Distance
引言 二维动态规划中最常见的是棋盘型二维动态规划. 即 func(i, j) 往往只和 func(i-1, j-1), func(i-1, j) 以及 func(i, j-1) 有关 这种情况下,时间 ...
- Hibernate知识点小结(二)
一.持久化对象和标识符 1.持久化类 配置完关系后,操作的实体对应的类,成为持久化类 (Customer) 2.持久化类标识符(oid:object id) 3.持久 ...
随机推荐
- Asp.net Core 2.1 Kestrel 现在支持 多协议处理(Tcp)
地址:https://github.com/davidfowl/MultiProtocolAspNetCore.git 在一个Kestrel服务上可以同时处理Tcp,Http,Https等多种协议. ...
- 基于Easyui框架的datagrid绑定数据,新增,修改,删除方法(四)
@{ ViewBag.Title = "xxlist"; } <script type="text/javascript" language=" ...
- POST与GET请求的区别
https://www.cnblogs.com/logsharing/p/8448446.html 返回主页 在途中# 博客园首页新随笔联系订阅管理 随笔 - 33 文章 - 5 评论 - 40 GE ...
- 一个钓鱼WiFi的破解
在开始前我们先安装下工具 git clone [url]https://github.com/P0cL4bs/WiFi-Pumpkin.git[/url] [/size] [size=4][size= ...
- Lucence工作原理
lucence 是一个高性能的java全文检索工具包,他使用倒排序文件索引结构,改结构和相应的生成算法如下: 一.设有两篇文章1和2 文章1的内容为:Tom lives in guangzh ...
- function参数
expr_without_variable { Z_LVAL($$.u.constant) = ; zend_do_pass_param(&$, ZEND_SEND_VAL, Z_LVAL($ ...
- 直接插入排序实现(Java)
直接插入排序介绍 直接插入排序的基本操作是将一个记录插入到已经排好序的有序表中,从而得到一个新的.记录数增1的有序表. 怎么理解呢?就是将n个待排序的元素看成一个有序表和一个无序表,开始时有序 ...
- C语言-apache mod(模块开发)-采用apxs开发实战(centos7.2 linux篇)
C语言-apache mod(模块开发)-采用apxs开发实战(centos7.2 linux篇) 名词解释:apxs apxs is a tool for building and installi ...
- (转) python学习笔记6--fraction
原文:https://blog.csdn.net/lemonwyc/article/details/37592883 fraction模块提供有关有理数的算术表达和计算,实际上就是分数的表达和计算.p ...
- 【C#小知识】C#中一些易混淆概念总结(五)---------深入解析C#继承
目录: [C#小知识]C#中一些易混淆概念总结--------数据类型存储位置,方法调用,out和ref参数的使用 [C#小知识]C#中一些易混淆概念总结(二)--------构造函数,this关键字 ...