前面的文章中,老周已向大伙伴们介绍了如何在终结点上使用地址头,只要服务是沿着该终结点调用的,那么每一次调用都会自动把地址头插入到SOAP消息的Header列表中。

而通过前一篇文章中的示例,大家也看到,客户端在调用服务时,必须指定与服务器完全一致的地址头,否则会验证失败。那是因为,在默认情况下,AddressFilter会对终结点的地址以及地址头进行校验。如果我们不希望使用默认校验行为,可以自定义一个MessageFiler,然后对传入的SOAP消息头进行验证。

MessageFilter是一个抽象类,它的结构如下:

    public abstract class MessageFilter
{
……
public abstract bool Match(MessageBuffer buffer); public abstract bool Match(Message message);
……
}

我们重点要实现Match方法,如果校验成功,则返回true,如果不通过就返回false。Match方法有两个重载,我们核心要做的是处理参数类型为Message的版本,而参数类型为MessageBuffer的版本,只需要从buffer中读出一条SOAP消息,并传递给bool Match(Message message)方法即可。

下面代码演示该处理。

        public override bool Match(MessageBuffer buffer)
{
Message msg = buffer.CreateMessage();
bool b= Match(msg);
msg.Close();
return b;
}

CreateMessage方法从字节缓冲区生成一条消息实例,然后调用另一个Match方法,并得到验证结果,最后把结果返回即可。由于此处的Message是从buffer产生的临时消息实例,因此用完后,可以调用Close方法释放掉。

接下来,我们重点实现参数类型为Message的Match方法重载。本例子我主要验证客户端的地址头中是否包含一个名为vip的XML元素,命名空间为member-vip,并且,XML元素内有一个名为star的attribute。假设它表示VIP会员的星级,比如一个购书服务程序,不同星级的VIP可以获得不折扣的优惠。

即客户端在调用时应提供这样的地址头:

<vip xmlns="member-vip" star="2" />

咱们这个自定义MessageFilter的任务是检查消息头中是否存在vip元素,且命名空间为member-vip,包含star特性。

        public override bool Match(Message message)
{
var hd = message.Headers.FirstOrDefault(h => h.Namespace == HEADER_NS && h.Name == HEADER_ELNAME);
if (hd == null) return false; XElement ele = message.Headers.GetHeader<XElement>(HEADER_ELNAME, HEADER_NS); if (ele.Attributes("star").Count() == )
{
return false;
}
return true;
}

筛选器是在消息调度阶段执行的,负责对终结点进行调度的是EndpointDispatcher类,它有一个AddressFilter属性,引用的类型正是MessageFilter的派生类。故,我们只要把自定义的消息筛选器实例赋给AddressFilter属性即可,那么,如何赋值呢?

WCF为每个服务部分都提供了Behavior,不同的Behavior用于扩展不同的对象。比如,对服务本身,可以用Service Behavior来扩展;对于终结点,可以用Endpoint Behavior来扩展;对于服务协定,可以用Contract Behavior来扩展,等等。Behavior可以对各个对象的功能进行扩充,但在扩展时应当注意,扩展点最好与behavior相对应,即,如果扩展点是扩展终结点的行为的,就应该用Endpoint Behavior来扩展,而不要用Cannel Behavior来扩展。

AddressFilter是作用在终结点上的,所以,在扩展时应该实现IEndpointBehavior接口。不管是哪一种类型的behavior,通常我们在实现时,会实现以下两个方法:

ApplyDispatchBehavior——指的是behavior在服务器上被应用后的处理。

ApplyClientBehavior——指在客户端应用behavior后的处理。

AddressFilter只需要在服务器端进行处理,而不必考虑客户端,所以,重点实现ApplyDispatchBehavior方法即可。

    public class MyEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{ } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{ } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.AddressFilter = new MyEndpointAddrFilter();
} public void Validate(ServiceEndpoint endpoint)
{ }
}

很简单,直接把自定义的MessageFilter实例赋值给AddressFilter属性就可以了。Validate方法是用来验证当前的终结点是否合法,本例中不用进行检验,如果你验证的话可以写上相应的代码,如果终结点不合法,直接抛出异常就行了。

随后,把这个自定义的终结点behavior插入到服务的终结点中即可。

            using (ServiceHost host=new ServiceHost(typeof(SV)))
{
foreach (var svep in host.Description.Endpoints)
{
if (svep.EndpointBehaviors.Contains(typeof(MyEndpointBehavior)) == false)
{
svep.EndpointBehaviors.Add(new MyEndpointBehavior());
}
} host.Open(); ………………

现在自定义的地址头筛选器已经起作用了。

目前这个Behavior不支持配置文件,只能使用代码来插入到ServiceEndpoint中。

要是希望该behavior可以通过配置文件使用,可以实现BehaviorExtensionElement抽象类。代码如下:

    public sealed class CustEndpointBehaviorElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get
{
return typeof(MyEndpointBehavior);
}
} protected override object CreateBehavior()
{
return new MyEndpointBehavior();
}
}

BehaviorType属性返回自定义behavior类型的Type,此处是MyEndpointBehavior类的Type。CreateBehavior方法返回自定义behavior的实例,此处当然是MyEndpointBehavior的实例了。

打开配置文件,在system.serviceModel节点下添加以下扩展声明:

  <system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="CustomEndpointBehavior" type="TestApp.CustEndpointBehaviorElement,TestApp"/>
</behaviorExtensions>
</extensions>
</system.serviceModel>

name指定的是随后在配置文件中使用该扩展时的元素名称,type指定类型,类名要包含命名空间,逗号后面是程序集名称。

现在可以在behaviors节点下声明了。

  <behaviors>
<endpointBehaviors>
<behavior name="svepbhv">
<CustomEndpointBehavior />
</behavior>
</endpointBehaviors>
</behaviors>

behavior的节点名称就是刚才在behaviorExtensions / add 下指定的name值。

最后,记得在endpoint节点上引用behavior配置。

   <endpoint address="http://localhost:2288/demo" …… behaviorConfiguration="svepbhv"/>

好了,如此一来,自定义的地址头筛选方案就完成了。

看起来像是复杂一些,其实也没什么,总结起来就是:扩MessageFilter --> 扩Behavior --> 应用behavior,另外附加的就是实现BehaviorExtensionElement类,这只是为了让其支持配置文件。

本文示例代码下载地址

【WCF】自定义地址头的筛选器的更多相关文章

  1. WCF自定义地址路由映射(不用svc文件)

    一般在创建WCF服务时会用Serivce.svc文件访问,地址如:http://localhost/applicationname/Serivce.svc/Name 现在用路由映射成:http://l ...

  2. 【WCF】为终结点地址应用地址头

    记得不久前,老周写过博文,探讨过在ContextScope以一定的范内向发出的消息中插入消息头,scope只能为特定的某一次服务操作的调用而添加SOAP头,要是需要在每次调用操作协定的时候都插上Hea ...

  3. WebApi:自定义筛选器

    最近在项目中有这样一个需求,记录每次Api访问的调用时间,运行时间,传入数据,返回数据等信息. 第一反应就是添加一个类,用来实现相应的功能,然后在方法的代码中添加,但是这样的话,需要修改所有的方法的代 ...

  4. Asp.Net MVC 页面代码压缩筛选器-自定义删除无效内容

    Asp.Net MVC 页面代码压缩筛选器 首先定义以下筛选器,用于代码压缩. /*页面压缩 筛选器*/ public class WhiteSpaceFilter : Stream { privat ...

  5. ASP.NET MVC 如何使用自定义过滤器(筛选器)

    继承*****Attribute(筛选器三种具体类)-->重写方法-->标记在控制器 或者 方法上面 或者 在FilterConfig中Add [类名(类属性 = 值)]还有[AllowA ...

  6. [转载]开发 Spring 自定义视图和视图解析器

    原文出处 http://www.ibm.com/developerworks/cn/java/j-lo-springview/ 概述 Spring 3.0 默认包含了多种视图和视图解析器,比如 JSP ...

  7. Magicodes.IE之导入导出筛选器

    总体设计   Magicodes.IE是一个导入导出通用库,支持Dto导入导出以及动态导出,支持Excel.Word.Pdf.Csv和Html.在本篇教程,笔者将讲述如何使用Magicodes.IE的 ...

  8. jQuery---jq基础了解(语法,特性),JQ和JS的区别对比,JQ和JS相互转换,Jquery的选择器(基础选择器,层级选择器,属性选择器),Jquery的筛选器(基本筛选器,表单筛选器),Jquery筛选方法

    jQuery---jq基础了解(语法,特性),JQ和JS的区别对比,JQ和JS相互转换,Jquery的选择器(基础选择器,层级选择器,属性选择器),Jquery的筛选器(基本筛选器,表单筛选器),Jq ...

  9. VS工具如何新建筛选器

    最近,遇到了一个问题,别人用VS工具新建了一个工程,不知道怎么的,就是没有办法新建筛选器. 今天,终于解决了,记录下,也希望能够帮助更多的人. 当我们的工程目录里的文件越来越多的时候,这时候需要建立帅 ...

随机推荐

  1. Jenkins 安装的HTML Publisher Plugin 插件无法展示ant生成的JunitReport报告

    最近在做基于jenkins ant  junit 的测试持续集成,单独ant junit生成的junitreport报告打开正常,使用Jenkins的HTML Publisher Plugin 插件无 ...

  2. Akka.net路径里的user

    因为经常买双色球,嫌每次对彩票号麻烦,于是休息的时候做了个双色球兑奖的小程序,做完了发现业务还挺复杂的,于是改DDD重做设计,拆分服务,各种折腾...,不过这和本随笔没多大关系,等差不多了再总结一下, ...

  3. CYQ.Data、ASP.NET Aries 百家企业使用名单

    如果您或您所在的公司正在使用此框架,请联系左侧的扣扣,告知我信息,我将为您添加链接: 以下内容为已反馈的用户,(收集始于:2016-08-08),仅展示99家: 序号 企业名称 企业网址 备注 1 山 ...

  4. ABP文档翻译--值对象

    本人是ABP初学者,在看英文文档和@tkb至简 的ABP框架理论研究总结(典藏版)时,发现大神@tkb至简中少了对Value Objects的翻译,看文档是新的,大神没时间把,小弟给补充上. 介绍 值 ...

  5. 使用Git Bash远程添加分支和简单部署你的静态页面

    新建一个分支:git branch mybranch(mybranch你的分支名字) 切换到你的新分支: git checkout mybranch 将新分支发布在github上: git push ...

  6. JavaScript中String对象的方法介绍

    1.字符方法 1.1 charAt() 方法,返回字符串中指定位置的字符. var question = "Do you like JavaScript?"; alert(ques ...

  7. jquery.each()

    $(selector).each(function(index,element)) index - 选择器的 index 位置 element - 当前的元素(也可使用 "this" ...

  8. Angular2 Hello World 之 2.0

    最近angular2正式版发布了,现在就趁热接着记录一下2.0版的Hello World.据说由RC6升级到2.0代码改动不是很大,在写的时候也感觉改动不是很大,这次记录还是以asp.net core ...

  9. java 字节流与字符流的区别

    字节流与和字符流的使用非常相似,两者除了操作代码上的不同之外,是否还有其他的不同呢?实际上字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的,而字符流在操作时使用了缓冲区,通过缓冲区再操作 ...

  10. 编写简单的Makefile文件

    makefile中的编写内容如下: www:hello.c x.h gcc hello.c -o hello clean: rm hello www:hello.c  x.h 表示生成www这个文件需 ...