WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序)...

WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序)
原文:WCF技术剖析之二十七: 如何将一个服务发布成WSDL[基于HTTP-GET的实现](提供模拟程序)

基于HTTP-GET的元数据发布方式与基于WS-MEX原理类似,但是ServiceMetadataBehavior需要做的更多额外的工作。原因很简单,由于在WS-MEX模式下,我们为寄宿的服务添加了相应的MEX终结点,那么当服务被成功寄宿后,WCF已经为元数据的消息交换建立了如图1所示的分发体系,我们需要做的仅仅是对MEX终结点的DispatchRuntime进行相应的定制而已。

image 图1 WCF服务端分发体系

但是如果采用HTTP-GET模式,实际上我们需要从ChannelDispatcher开始,重新构建整个分发体系。接下来,我们在《WS-MEX原理》提供实例的基础上,对我们自定义ServiceMetadataBehaviorAttribute进行进一步的完善,使之同时对两种模式的元数据发布提供支持。 (Source Code从这里下载)

首先,我们需要定义一个新的服务契约接口:IHttpGetMetadata,Get操作处理任何形式的消息请求,因为它的输入参数和返回类型均为Message,并且Action和ReplyAction为*。

   1: using System.ServiceModel;
   2: using System.ServiceModel.Channels;
   3: namespace ServiceMetadataBehaviorSimulator
   4: {
   5:     [ServiceContract(Name = "IHttpGetMetadata", Namespace = "http://www.artech.com/")]
   6:     public interface IHttpGetMetadata
   7:     {
   8:         [OperationContract(Action = "*", ReplyAction = "*")]
   9:         Message Get(Message msg);
  10:     }
  11: }

然后我们让前面定义的MetadataProvisionService实现IHttpGetMetadata接口,在这里无需再写任何多余的代码,因为MetadataProvisionService已经具有了一个Get方法。

   1: public class MetadataProvisionService : IMetadataProvisionService, IHttpGetMetadata
   2: {
   3:       //省略成员
   4: }

接下来的工作就是构建一个全新的ChannelDispatcher,以及关联EndpointDispatcher,最后对EndpointDispatcher的DispatchRuntime进行定制。为此,我单独写了一个方法:CreateHttpGetChannelDispatcher。

   1: [AttributeUsage(AttributeTargets.Class)]
   2: public class ServiceMetadataBehaviorAttribute : Attribute, IServiceBehavior
   3: {
   4:     //其他成员
   5: private const string SingletonInstanceContextProviderType = "System.ServiceModel.Dispatcher.SingletonInstanceContextProvider,System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
   6:      private const string SyncMethodInvokerType = "System.ServiceModel.Dispatcher.SyncMethodInvoker,System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
   7:      private const string MessageOperationFormatterType = "System.ServiceModel.Dispatcher.MessageOperationFormatter, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
   8:  
   9:     private static void CreateHttpGetChannelDispatcher(ServiceHostBase host, Uri listenUri, MetadataSet metadata)
  10:     {
  11:         //创建Binding
  12:         TextMessageEncodingBindingElement messageEncodingElement = new TextMessageEncodingBindingElement() { MessageVersion = MessageVersion.None };
  13:         HttpTransportBindingElement transportElement = new HttpTransportBindingElement();
  14:         Utility.SetPropertyValue(transportElement, "Method", "GET");
  15:         Binding binding = new CustomBinding(messageEncodingElement, transportElement);
  16:  
  17:         //创建ChannelListener
  18:         IChannelListener listener = binding.BuildChannelListener<IReplyChannel>(listenUri, string.Empty, ListenUriMode.Explicit, new BindingParameterCollection());
  19:         ChannelDispatcher dispatcher = new ChannelDispatcher(listener, "ServiceMetadataBehaviorHttpGetBinding", binding) { MessageVersion = binding.MessageVersion };
  20:  
  21:         //创建EndpointDispatcher
  22:         EndpointDispatcher endpoint = new EndpointDispatcher(new EndpointAddress(listenUri), "IHttpGetMetadata", "http://www.artech.com/");
  23:  
  24:         //创建DispatchOperation,并设置DispatchMessageFormatter和OperationInvoker
  25:         DispatchOperation operation = new DispatchOperation(endpoint.DispatchRuntime, "Get", "*", "*");
  26:         operation.Formatter = Utility.CreateInstance<IDispatchMessageFormatter>(MessageOperationFormatterType, Type.EmptyTypes, new object[0]);
  27:         MethodInfo method = typeof(IHttpGetMetadata).GetMethod("Get");
  28:         operation.Invoker = Utility.CreateInstance<IOperationInvoker>(SyncMethodInvokerType, new Type[] { typeof(MethodInfo) }, new object[] { method });
  29:         endpoint.DispatchRuntime.Operations.Add(operation);
  30:  
  31:         //设置SingletonInstanceContext和InstanceContextProvider
  32:         MetadataProvisionService serviceInstance = new MetadataProvisionService(metadata);
  33:         endpoint.DispatchRuntime.SingletonInstanceContext = new InstanceContext(host, serviceInstance);
  34:         endpoint.DispatchRuntime.InstanceContextProvider = Utility.CreateInstance<IInstanceContextProvider>(SingletonInstanceContextProviderType, new Type[] { typeof(DispatchRuntime) }, new object[] { endpoint.DispatchRuntime });
  35:         dispatcher.Endpoints.Add(endpoint);
  36:  
  37:         //设置ContractFilter和AddressFilter
  38:         endpoint.ContractFilter = new MatchAllMessageFilter();
  39:         endpoint.AddressFilter = new MatchAllMessageFilter();
  40:  
  41:         host.ChannelDispatchers.Add(dispatcher);
  42:     }
  43: }

大体上介绍一下创建ChannelDispatcher的逻辑。首先创建绑定对象,该绑定由两个绑定元素构成:TextMessageEncodingBindingElement和HttpTransportBindingElement,这些因为元数据请求消息就是单纯的HTTP-GET请求消息,并不是一个SOAP,所以需要将HttpTransportBindingElement的消息版本设为None,并将Method属性(这是一个internal属性)设为GET。

然后利用创建的绑定对象创建ChannelListener,并基于该ChannelListener创建ChannelDispatcher对象。当ChannelDispatcher成功创建,开始创建EndpointDispatcher对象,并定制该EndpointDispatcher的DispatchRuntime。这其中包括创建DispatchOperation对象以及相关的消息格式化器以及操作执行器。然后是我们熟悉的对InstanceContextProvider和SingletonInstanceContext的设定。最后需要设置EndpointDispatcher的两个消息筛选器:契约筛选器地址筛选器,在这将它们设置成MatchAllMessageFilter类型,使之能够匹配所有的请求消息。关于WCF的消息筛选机制,在《WCF技术剖析(卷1)》第2章有详细介绍。

待DispatchRuntime被成功定制,将创建的EndpointDispatcher添加到ChannelDispatcher的EndpointDispatcher列表,最终再将ChannelDispatcher添加到ServiceHost的ChannelDispatcher列表中。

然后,我们在ServiceMetadataBehaviorAttribute添加两个属性:HttpGetEnabledHttpGetUrl,前者表示是否采用基于HTTP-GET的元数据发布模式,后者指定元数据发布的地址。并将上面定义的CreateHttpGetChannelDispatcher添加到ApplyDispatchBehavior方法中。

   1: [AttributeUsage(AttributeTargets.Class)]
   2: public class ServiceMetadataBehaviorAttribute : Attribute, IServiceBehavior
   3: {
   4:     //其他成员
   5:     public bool HttpGetEnabled
   6:     { get; set; }
   7:     public string HttpGetUrl
   8:     { get; set; }
   9:     public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
  10:     {
  11:         MetadataSet metadata = GetExportedMetadata(serviceDescription);
  12:         CustomizeMexEndpoints(serviceDescription, serviceHostBase, metadata);
  13:         if (this.HttpGetEnabled)
  14:         {
  15:             CreateHttpGetChannelDispatcher(serviceHostBase, new Uri(this.HttpGetUrl), metadata);
  16:         }    
  17: }
  18: }

那么现在我们就可以通过下面的方式将ServiceMetadataBehaviorAttribute应用到我们的CalculatorService,并通过HttpGetUrl属性指定原数据发布的目标地址:

   1: [ServiceMetadataBehavior(HttpGetEnabled = true, HttpGetUrl = "http://127.0.0.1:9999/calculatorservice/mex")]
   2: public class CalculatorService : ICalculator, IMetadataProvisionService
   3: {
   4:    //省略成员
   5: }

如果CalculatorService被成功寄宿,直接通过浏览器访问元数据发布的地址(http://127.0.0.1:9999/calculatorservice/mex),你可以看到与图2一样的结果。 

image

图2 通过IE获取发布的元数据

作者:Artech
出处:http://artech.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
posted on 2015-07-10 15:25 NET未来之路 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/4635861.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/397877.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络配置 rpm yum

vm0 vm1 vm2安装vmware后&#xff1a;安装vmware tools工具1 物理机和虚拟机复制 粘贴 unity模式 共享文件夹等功能2设置共享文件夹网络相关命令# lspci |grep eth 查看驱动卡信息#mii-tool eth1eth1:negoriated 100baseTX-FD,link ok ,如果fail表示网线没连接好ifconfig 查看…

)标识符不能是c语言的关键字,标识符不能是C的关键字

满意答案tftgcl882014.08.07采纳率&#xff1a;58% 等级&#xff1a;9已帮助&#xff1a;3967人所谓关键字就是已被Turbo C2.0本身使用&#xff0c; 不能作其它用途使用的字。例如关键字不能用作变量名、函数名等。Turbo C2.0有以下关键字:Turbo C2.0扩展的共11个asm …

不同类的方法 事务问题_【高中地理】描述类问题的答题方法

一、描述地理位置的特征及意义位置&#xff1a;半球位置、纬度位置、海陆位置、相对位置&#xff08;邻省或邻国、地形区、地势阶梯交界处、气候区、图例中的特殊地理事物&#xff09;、板块位置、交通位置等。意义&#xff1a;①所处位置&#xff08;是否是重要分界线&#xf…

JqGrid 列时间格式化

{name:createTime,index:createTime,label:"创建时间", editable:false,formatter:"date",formatoptions: {srcformat:Y-m-d H:i:s,newformat:Y-m-d H:i:s}}, 转载于:https://www.cnblogs.com/youmingkuang/p/9095497.html

Debian 系统安装 Nagios 服务器监控端

安装apt-get updateapt-get install nagios* perlapt-get install --no-install-recommends pnp4nagiosapt-get install apache2 apache2-utils php5 php-pear 修改npcd设置# vim /etc/default/npcdRun"yes"# service npcd start 添加process_perfdata.pl执行权限ch…

spark-stream 访问 Redis

最近在spark-stream上写了一些流计算处理程序&#xff0c;程序架构如下 程序运行在Spark-stream上&#xff0c;我的目标是kafka、Redis的参数都支持在启动时指定。 在写代码时参考了这篇文章 https://www.iteblog.com/archi...&#xff0c;该文讲的比较清楚&#xff0c;但是有两…

c语言打印空心等腰梯形乐学,C语言做激光发射

/*C语言做激光发射器游戏&#xff0c;按上下左右箭头键移动发射器&#xff0c;按空格键发射激光&#xff0c;按Esc键结束游戏*/#include #include #include void main(){int i,j;//定义循环变量int x15,y10;//定义横坐标与纵坐标初始值char in;int fire0;int kill0;int nx10;//…

东软睿云用户认证_【硬件资讯】尘埃落定!11代酷睿规格曝光!i7、i9难分差距,退回8核16线程!...

新闻①&#xff1a;Intel第11代酷睿处理器规格曝光&#xff0c;旗舰i9-11900K与i7-11700K同为8核16线程Intel的代号为Rocket Lake-S的第11代酷睿台式机CPU阵容将于明年推出&#xff0c;其中四个型号的规格现已曝光。拥有8个Cypress Cove核心、5.3GHz、PL2功耗限制250W的酷睿i9-…

环上的游戏

环上的游戏&#xff08;cycle&#xff09;有一个取数的游戏。初始时&#xff0c;给出一个环&#xff0c;环上的每条边上都有一个非负整数。这些整数中至少有一个0。然后&#xff0c;将一枚硬币放在环上的一个节点上。两个玩家就是以这个放硬币的节点为起点开始这个游戏&#xf…

python基础课程_2学习笔记3:图形用户界面

图形用户界面 丰富的平台 写作Python GUI程序前&#xff0c;须要决定使用哪个GUI平台。 简单来说&#xff0c;平台是图形组件的一个特定集合。能够通过叫做GUI工具包的给定Python模块进行訪问。工具包 描写叙述 Tkinter 使用Tk平台。非常easy得到。半标准。 wxpython 基于…

vim编辑器之按键说明

viim编辑器文本:纯文本,ASCII test;文本编辑种类:行编辑器:sed全屏编辑器:nano,vi其他编辑器:gedit 一个简单的图形编辑器gvim 一个vim编辑器的图形版本 一.打开文件几种方法命令格式:vim [options] [files]常用选项:#:打开文件后,直接让光标处于第#行的行首/PATTERN:打开…

idea ssm打war包_IDEA下从零开始搭建SpringBoot工程

SpringBoot的具体介绍可以参看其他网上介绍&#xff0c;这里就不多说了&#xff0c;就这几天的学习&#xff0c;个人理解&#xff0c;简而言之&#xff1a;如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring&#xff0c;MyBatis&#xff0c;Netty源码分析的朋友…

c语言一维数组转化为二维矩阵,js将一维数组转化为二维数组

遇到的问题&#xff1a;后端返回的是一组一维数组&#xff0c;但是需要展示的格式是二维数组&#xff0c;常见的场景举例&#xff1a;后台返回10个长度的数组&#xff0c;需要分成3个一组展示在banner上。例&#xff1a;[1,2,3,4,5,6,7,8,9,10] > [[1,2,3], [4,5,6], [7,8…

nano使用说明

Main nano help text The nano editor is designed to emulate 仿真、模拟 the functionality and ease-of-use of the UW Pico text editor. There are four main sections of the editor. The top line shows the program version, the current filename being edited, and w…

dataframe 众数的方法_学习数据分析数据方法论 [描述性统计分析]

数理统计&#xff1a;数理统计是以概率论为基础&#xff0c;研究社会和自然界中大量随机现象数量变化基本规律的一种方法。分为&#xff1a;描述统计(描述统计的任务是搜集资料&#xff0c;进行整理、分组&#xff0c;编制次数分配表&#xff0c;绘制次数分配曲线&#xff0c;计…

c语言高级语言期中测试答案,上海理工大学C语言2011期中试题和答案

C语言2010/2011学年 第二学期 期中测试高级语言程序设计(C)试卷 A □BA1. 输入一行字符&#xff0c;统计其中的英文字母个数。#include void main(){ char ch;int n0;printf(“Input a string:\n”);while(1){ chgetchar();if (ch \n ) break;if (ch> a && ch< z…

前端基础进阶(十):面向对象实战之封装拖拽对象

https://segmentfault.com/a/1190000012646488 https://yangbo5207.github.io/wutongluo/ 说明&#xff1a;此处只是记录阅读前端基础进阶的理解和总结&#xff0c;如有需要请阅读上面的链接 1.如何让元素动起来 要让元素动起来就要修改元素的top、left 、translate 属性。因为…

iOS - LocalCache 本地数据缓存

1、自定义方式本地数据缓存 1.1 自定义缓存 1 沙盒路径下的 Library/Caches 用来存放缓存文件&#xff0c;保存从网络下载的请求数据&#xff0c;后续仍然需要继续使用的文件&#xff0c;例如网络下载的离线数据&#xff0c;图片&#xff0c;视频文件等。该目录中的文件系统不会…

如何构建ASP.NET MVC4JQueryAJaxJSon示例

背景&#xff1a; 博客中将构建一个小示例&#xff0c;用于演示在ASP.NET MVC4项目中&#xff0c;如何使用JQuery Ajax。 直接查看JSon部分 步骤&#xff1a; 1&#xff0c;添加控制器(HomeController)和动作方法(Index),并为Index动作方法添加视图(Index.cshtml),视图中HTML如…

echarts 有引导线和内部文字_点、线、面构图的异同以及相互转化

点、线、面构图既有相似性&#xff0c;又有差异性。相似的是都有对齐、强调、群组、重复、突出层次的作用&#xff0c;不同的是点的特点是聚焦、线的特点是运动和方向性&#xff0c;面的特性是体量感、稳定性。点的情感最弱&#xff0c;线、面的情感要比点丰富。一、点、线、面…