【WCF】为终结点地址应用地址头
记得不久前,老周写过博文,探讨过在ContextScope以一定的范内向发出的消息中插入消息头,scope只能为特定的某一次服务操作的调用而添加SOAP头,要是需要在每次调用操作协定的时候都插上Header,一种方法可以自定义实现消息拦截器,拦截服务传输的消息,并向消息添加header,关于拦截器,老周后面会介绍。另一种方法,就是本文的主题——地址头。
我们都知道,服务对外公开后,客户端可以把消息传输到终结点指定的监听URI上,终结点收到消息后,通过Dispatcher把消息调度到对应用的通道(channel)上,最后找到对应的服务协定,并将收到的输入参数传给服务操作,进而调用服务。服务调用后,操作结果会沿着相反的顺序传回客户端,即返回的内容被包装为SOAP消息,放入通道栈,再输送回调度程序,最后发回客户端。
终结点以Binding确定通信协议和方式,并必须指定一个有效的地址来接收调用消息,为了能够调用服务操作,还得指定一个服务协定。如果为终结点的地址加上header,那么,只要服务是通过该终结点调用的,则每一次调用都会自动把地址头插入到传出的消息中。这样我们就不必要每次调用都去添加消息头了。
不知不觉就说了一堆F话,下面,咱们来做一个例子,这个例子是通过代码来指定地址头。
首先,当然是声明服务协定。
[ServiceContract]
public interface IDemo
{
[OperationContract]
string Hello(string name);
}
然后,实现服务类。
class MyService : IDemo
{
public string Hello(string name)
{
return $"Hello, {name}.";
}
}
服务的实现比较简单,我们的重点不是这些,所以随意弄弄。
接下来就是重点了,咱们用代码来添加地址头。地址头可以添加任意内容,最终会被序列化为XML元素,插入到消息头列表中。假设,我们定义一个名为AddressInfo的数据协定。
[DataContract(Namespace = "addr-info", Name = "addr_info")]
public class AddressInfo
{
/// <summary>
/// 省
/// </summary>
[DataMember(Name = "province")]
public string Province { get; set; } /// <summary>
/// 市
/// </summary>
[DataMember(Name = "city")]
public string City { get; set; } /// <summary>
/// 详细地址
/// </summary>
[DataMember(Name = "details")]
public string DetailAddress { get; set; } /// <summary>
/// 邮政编号
/// </summary>
[DataMember(Name = "zipcode")]
public string ZipCode { get; set; }
}
最后建立服务寄宿,并添加终结点。
Uri endpointAddress = new Uri("http://localhost:2016/demo");
using(ServiceHost host=new ServiceHost(typeof(MyService)))
{
// 添加终结点,必须在Open之前完成。
// Open之后修改就不会生效了。
// 1、准备地址头
AddressInfo addrinfo = new AddressInfo
{
Province = "广东省",
City = "东莞市",
ZipCode = "523xxx",
DetailAddress = "火星镇XX小区非人道主义研究大厦K008室"
};
// 创建Header
AddressHeader hd = AddressHeader.CreateAddressHeader(addrinfo);
// 2、创建EndpointAddress
EndpointAddress epaddress = new EndpointAddress(endpointAddress, hd);
// 3、创建终结点实例
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
ServiceEndpoint svendp = new ServiceEndpoint(ContractDescription.GetContract(typeof(IDemo)), binding, epaddress);
// 4、添加终结点到host中
host.AddServiceEndpoint(svendp);
// 5、打开服务
try
{
host.Open();
Console.WriteLine("服务已启动。");
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
AddressHeader类表示一个消息头,它是抽象类,提供内部实现,使用时应调用它公开的CreateAddressHeader静态方法来得到一个AddressHeader实例,参数必须是一个可以XML序列化的对象,这里用的是我刚刚定义的数据协定,它当然可以XML序列化了。
如果是要创建带有一些基本类型值的头,可以这样用:
AddressHeader hd3 = AddressHeader.CreateAddressHeader("element", "my-namespace", );
第一个参数是XML元素的名字,第二个参数是XML命名空间,一般以URI形式表示,当然你可以随便写,只要不带非法字符就行。第三个参数是Header中的内容,即value,这里用的是整数值300。
地址头可以在实例化EndpointAddress时通过构造函数传递。
EndpointAddress epaddress = new EndpointAddress(endpointAddress, hd);
下面,我们来调用一下服务。
// 1、准备地址头
AddressInfo cl_addrinfo = new AddressInfo();
cl_addrinfo.Province = "广东省";
cl_addrinfo.City = "东莞市";
cl_addrinfo.DetailAddress = "火星镇XX小区非人道主义研究大厦K008室";
cl_addrinfo.ZipCode = "523xxx";
AddressHeader hdclient = AddressHeader.CreateAddressHeader(cl_addrinfo);
// 2、创建终结点地址,并附带地址头
EndpointAddress clepaddr = new EndpointAddress(endpointAddress, hdclient);
// 3、创建binding,必须与服务器的定义一致
BasicHttpBinding clientbinding = new BasicHttpBinding(BasicHttpSecurityMode.None);
// 4、创建通道工厂
ChannelFactory<IDemo> factory = new ChannelFactory<IDemo>(clientbinding, clepaddr);
// 创建通道,由于内部已实现,可以用协定直接作为通道对象
IDemo channel = factory.CreateChannel();
// 5、调用服务
string response = channel.Hello("Jack");
Console.WriteLine("调用结果:{0}", response);
factory.Close();
插入到消息在的地址头如下图所示。

由于服务器在定义终结点地址时插入了地址头,所以,在客户端调用时,终结点地址和附带的地址头必须要与服务器所指定的一致,否则会调用失败。
比如,我们把上面客户端调用代码中的地址头信息改为“广州市”,然后再次调用服务。
AddressInfo cl_addrinfo = new AddressInfo();
cl_addrinfo.Province = "广东省";
cl_addrinfo.City = "广州市";
这时候调用服务,你会看到以下精彩一幕。

所以说啊,客户端在调用时,必须提供与服务器指定完全相同的地址头。这是默认的地址筛选方案导致的,默认情况下,两者的地址头必须完全一样才能通过筛选。
那么,有朋友一定会问,能不能让服务器和客户端所指定的地址头不一样,但又可以让服务器匹配筛选呢?关于这个问题嘛,老周会在下一篇烂文中给大伙伴们介绍。
-----------------------------------------------------------------
上面说了用代码的方式来指定地址头,那么,对应地,肯定得看看如何在配置文件中指定地址头了。
由于配置文件本身就是一个XML文件,所以,在配置文件中指定就更好办了,直接写XML节点就行了。
比如,服务器可以这样:
<endpoint address="http://localhost:1399/demo" binding="basicHttpBinding" contract="Test0160804.IDemo">
<headers>
<book xmlns="book-store">
<name>三国演义</name>
<date>--</date>
<price>39.88</price>
</book>
</headers>
</endpoint>
<headers>节点下可以添加任意XML节点,只要XML元素是完整的就行了。在处理SOAP消息时,是通过XML命名空间和元素名称来查找消息头的,所以,老周建议大家不要添加元素名和命名空间相同的多个头。比如这样
<headers>
<book xmlns="book-store">
<name>三国演义</name>
<date>2007-3-19</date>
<price>39.88</price>
</book>
<book xmlns="book-store">
<name>红岩</name>
<date>2003-10-5</date>
<price>26.5</price>
</book>
</headers>
当然,这样添加地址头,只要客户端调用时提供相同的地址头,是不会出错的,不过,如果你希望在代码中通过GetHeader<T>或FindHeader方法来获取消息头的话,要是找到元素名和命名空间相同的头,就会发生异常。这时候,你就只好使用最笨的方法来读取消息头了——读取普通XML文档的方式。
所以,为了减少处理麻烦,最好不要在地址头中放置相同结构的XML元素,当然了,如果你不打算在代码中读取消息头,而仅仅是为了加强客户端与服务器的地址验证,就无所谓了。
在客户端,配置文件中指定的地址头必须与服务器的一致。
<client>
<endpoint name="clep" address="http://localhost:1399/demo" binding="basicHttpBinding" contract="Test0160804.IDemo">
<headers>
<book xmlns="book-store">
<name>三国演义</name>
<date>2007-3-19</date>
<price>39.88</price>
</book>
<book xmlns="book-store">
<name>红岩</name>
<date>2003-10-5</date>
<price>26.5</price>
</book>
</headers>
</endpoint>
</client>
这样做是为了增强对终结点地址的验证。
有关如何自行定义地址头筛选方案,而不是使用默认的完全匹配方案,下次再聊,88。
示例代码下载:http://files.cnblogs.com/files/tcjiaan/addressheaderSample.zip
【WCF】为终结点地址应用地址头的更多相关文章
- 彻底明白IP地址——IP地址的介绍
彻底明白IP地址——IP地址的介绍 [ 作者:担子 转贴自:赛迪网 点击数:9692 更新时间:2004-12-22 ] IP地址的介绍 1.IP地址的表示方法 IP地址 = ...
- 纯真IP根据IP地址获得地址
<?php /** * 纯真IP根据IP地址获得地址 */ class ipLocation { public $fp; public $firstip; //第一条ip索引的偏移地址 publ ...
- QT通过IP地址定位地址(用get方法取数据)
通过IP地址定位地址,是要通过查询数据库,如果自己做一个这样的数据库工作量就比较大,所以在网上找了一个查询IP地址的网址,通过调用这个网址查询来实现,但是这个有一定的弊端,如果没有网络或者这个网址不可 ...
- 基于echarts 24种数据可视化展示,填充数据就可用,动手能力强的还可以DIY(演示地址+下载地址)
前言 我们先跟随百度百科了解一下什么是"数据可视化 [1]". 数据可视化,是关于数据视觉表现形式的科学技术研究. 其中,这种数据的视觉表现形式被定义为,一种以某种概要形式抽提出来 ...
- 【WCF】终结点的监听地址
终结点主要作用是向客户端公开一些信息入口,通过这个入口,可以找到要调用的服务操作.通常,终结点会使用三个要素来表述,我记得老蒋(网名:Artech,在园子里可以找到他)在他有关WCF的书里,把这三要素 ...
- WCF: 没有终结点在侦听可以接受消息的 这通常是由于不正确的地址或者 SOAP 操作导致的。
问题: 由于我这里的wcf服务是采用“BasicHttpBinding”的方式,即安全绑定模式,客户端在引用这个服务后所生成的终结点配置(endpoint )就变成了<endpoint ...
- WCF 服务的ABC之地址(五)
地址 Address 在WCF中,每个服务都有一个唯一的地址(Address). 地址包含两个重要的元素:服务位置及传输协议. 服务位置包含目标机器名.站点.通信端口.管道(或队列),以及一个可选的特 ...
- WCF全面解析第二章 地址(Adress)
2.1 统一资源标识(URL) 2.1.1 Http/Https 2.1.2 Net.TCP 2.1.3 Net.Pipe WCF只将命名管道专门用于同一台机器的跨进程通信. 2.1.4 Net.Ms ...
- Python requests 调Jenkins登录接口,返回404,但请求地址、请求头、消息主题和抓包的内容都一样
#coding=utf-8import requests url = "http://localhost:8080/jenkins/j_acegi_security_check"h ...
随机推荐
- ASP.NET Aries 入门开发教程4:查询区的下拉配置
背景: 今天去深圳溜达了一天,刚回来,看到首页都是微软大法好,看来离.NET的春天就差3个月了~~ 回到正题,这篇的教程讲解下拉配置. 查询区的下拉配置: 1:查询框怎么配置成下拉? 在配置表头:格式 ...
- 发布:.NET开发人员必备的可视化调试工具(你值的拥有)
1:如何使用 1:点击下载:.NET可视化调试工具 (更新于2016-12-29 19:11:00) (终于彻底兼容了部分VS环境下无法使用的问题) 2:解压RAR后执行:CYQ.VisualierS ...
- 【前端性能】高性能滚动 scroll 及页面渲染优化
最近在研究页面渲染及web动画的性能问题,以及拜读<CSS SECRET>(CSS揭秘)这本大作. 本文主要想谈谈页面优化之滚动优化. 主要内容包括了为何需要优化滚动事件,滚动与页面渲染的 ...
- HTML渲染过程详解
无意中看到寒冬关于前端的九个问题,细细想来我也只是对第一.二.九问有所了解,正好也趁着这个机会梳理一下自己的知识体系.由于本人对http协议以及dns对url的解析问题并不了解,所以这里之探讨url请 ...
- ABP文档 - SignalR 集成
文档目录 本节内容: 简介 安装 服务端 客户端 连接确立 内置功能 通知 在线客户端 帕斯卡 vs 骆峰式 你的SignalR代码 简介 使用Abp.Web.SignalR nuget包,使基于应用 ...
- HTML5 sessionStorage会话存储
sessionStorage 是HTML5新增的一个会话存储对象,用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据.本篇主要介绍 sessionStorage(会话存储) ...
- AbpZero--1.如何开始
1.加群 群号:104390185,下载这个文件并解压 用VS2015打开aspnet-zero-1.9.0.1 2.修改Web项目web.config连接字符串 <add name=" ...
- ADO.NET一小记-select top 参数问题
异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 最近使用ADO.NET的时候,发现select top @count xxxx 不 ...
- SAP CRM 用户界面对象类型和设计对象
在CRM中的用户界面对象类型的帮助下,我们可以做这些工作: 进行不同的视图配置 创建动态导航 从设计层控制字段标签.值帮助 控制BOL对象的属性的可视性 从导航栏访问自定义组件 一个用户界面对象类型之 ...
- 【腾讯Bugly干货分享】一步一步实现Android的MVP框架
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5799d7844bef22a823b3ad44 内容大纲: Android 开发 ...