[老老实实学WCF] 第二篇 配置WCF

老老实实学WCF

第二篇 配置WCF

 

在上一篇中,我们在一个控制台应用程序中编写了一个简单的WCF服务并承载了它。先回顾一下服务端的代码:

 

[csharp] view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5.   
  6. using System.ServiceModel;  
  7. using System.ServiceModel.Description;  
  8.   
  9. namespace HelloWCFService  
  10. {  
  11.     class Program  
  12.     {  
  13.         static void Main(string[] args)  
  14.         {  
  15.             Uri baseAddress = new Uri("http://localhost:8000/MyService");  
  16.   
  17.             ServiceHost host = new ServiceHost(typeof(HelloWCFService), baseAddress);  
  18.   
  19.             host.AddServiceEndpoint(typeof(IHelloWCFService), new WSHttpBinding(), "HelloWCFService");  
  20.   
  21.             ServiceMetadataBehavior smb = new ServiceMetadataBehavior();  
  22.             smb.HttpGetEnabled = true;  
  23.             host.Description.Behaviors.Add(smb);  
  24.   
  25.             host.Open();  
  26.   
  27.             Console.WriteLine("Service is Ready");  
  28.             Console.WriteLine("Press Any Key to Terminate...");  
  29.             Console.ReadLine();  
  30.   
  31.             host.Close();  
  32.               
  33.         }  
  34.     }  
  35.   
  36.     [ServiceContract]  
  37.     interface IHelloWCFService  
  38.     {  
  39.         [OperationContract]  
  40.         string HelloWCF();  
  41.     }  
  42.   
  43.     public class HelloWCFService : IHelloWCFService  
  44.     {  
  45.         public string HelloWCF()  
  46.         {  
  47.             return "Hello WCF!";  
  48.         }  
  49.     }  
  50. }  


所有的这些代码都写在program.cs中,干净清爽。

 

我们稍微审视一下这段程序会发现,我们用了很多的代码来定制服务的特性,例如基地址、终结点、绑定、行为等。这些都叫做配置。而真正对服务的本身的定义是很少的(主逻辑就是返回一个字符串而已),因此我们不难看出,WCF的编程中配置占了很大的比重。

 

WCF的配置选项是很多的,我们这里只考虑最简单的情况。我们在定义和实现了服务协定后,至少应该做哪些配置才能让服务运行起来呢?

(1) 依据服务实现类配置一个服务(ServiceHost)。

(2) 指定一个基地址(如果终结点中指定了绝对地址,这步可以省略)。

(3) 建立一个终结点,并为其指定地址、绑定和服务协定。

(4) 建立一个元数据交换终结点。

(5) 为服务添加一个行为来启用元数据交换。

虽然在.Net 4.0下微软提供了简化配置,我们甚至可以一行配置都不做,但是为了搞清楚配置的基本原理,我们暂时不考虑简化配置的情况。

 

以下这些配置是我们必须要做的,我们从代码中可以看到以上几种配置相应语句:

 

建立基地址:

[csharp] view plain copy
  1. Uri baseAddress = new Uri("http://localhost:8000/MyService");  


建立服务:

[csharp] view plain copy
  1. ServiceHost host = new ServiceHost(typeof(HelloWCFService), baseAddress);  


建立终结点并指定地址、绑定和服务协定:

[csharp] view plain copy
  1. host.AddServiceEndpoint(typeof(IHelloWCFService), new WSHttpBinding(), "HelloWCFService");  


添加元数据交换终结点并添加启用元数据交换行为

[csharp] view plain copy
  1. ServiceMetadataBehavior smb = new ServiceMetadataBehavior();  
  2. smb.HttpGetEnabled = true;  
  3. host.Description.Behaviors.Add(smb);  


看上去清楚明白,但是只是看上去很美,这样的配置方式存在弊端,例如基地址,如果当服务部署之后迁移了服务器,基地址发生变化,我们必须修改源程序并重新 编译重新部署才能实现这个要求。对于其他的配置选项亦是如此。这对于产品环境是不能接受的。好在WCF提供针对这个问题的解决方案:配置文件。

 

我们把对服务的配置写在应用程序的配置文件中(IIS程序是web.config 其他程序是app.config),当配置发生改变的时候我们就不用重新编译程序集了。

 

配置文件的写法很复杂,有很多选项,为了便于上手,我们先从跟本例相关的选项开始。

 

在配置文件中,根节是<configuration>,所有的配置元素都位于其中。对于WCF服务的配置部分,最外层的节是<system.serviceModel>,所以配置文件中至少先应该是这个样子:

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.       
  5.   </system.serviceModel>  
  6. </configuration>  


现在我们准备开始配置一个服务,服务配置元素标签为<services></services>, 是<system.serviceModel>的子节,在一个宿主上可以承载许多服务,每一个服务 用<service></service>来配置,它是<services>的子节。在配 置<service>前,我们还要先添加一个基地址配置,基地址用<baseaddress>描述,他 是<host>的子节,<host>是<service>的子节。

晕了么...慢慢来。

先把<services>节加上,这里可以容纳许多服务,注意这个是带s的

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.     <services>  
  5.         
  6.     </services>      
  7.   </system.serviceModel>  
  8. </configuration>  


在<services>的怀抱中,我们添加一个<service>,这是我们要配置的服务本体,注意这个是不带s的

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.     <services>  
  5.       <service>  
  6.           
  7.       </service>  
  8.     </services>      
  9.   </system.serviceModel>  
  10. </configuration>  


在<service>中,添加一个基地址,先添加一个<host>再添加一个<baseaddress>

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.     <services>  
  5.       <service>  
  6.         <host>  
  7.           <baseAddresses>  
  8.             <add baseAddress="http://localhost:8000/MyService"/>  
  9.           </baseAddresses>  
  10.         </host>  
  11.       </service>  
  12.     </services>      
  13.   </system.serviceModel>  
  14. </configuration>  

 

到这里,基地址的部分已经完成,对应代码中的位置你找到了么?

服务的配置还差一点,我们在代码中为服务指定了实现类型,在配置文件中如何指定呢?就用<service>标签的name属性,指定的时候后要用完全限定名(带着命名空间)

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.     <services>  
  5.       <service name="HelloWCFService.HelloWCFService">  
  6.         <host>  
  7.           <baseAddresses>  
  8.             <add baseAddress="http://localhost:8000/MyService"/>  
  9.           </baseAddresses>  
  10.         </host>  
  11.       </service>  
  12.     </services>      
  13.   </system.serviceModel>  
  14. </configuration>  

我这个例子举的不好了,命名空间和实现类型是一个名字,要注意区分。

 

到这里,服务也配置完了,对应代码的位置翻上去找一下。

接下来配置终结点,终结点用<endpoint>元素表示,正如代码实现中的参数,在配置中也需要一一指定地址、 绑定和服务协定接口,分别用address、binding和contract属性来表示,当然<endpoint>也 是<service>的子节,毕竟他是属于服务的嘛。

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.     <services>  
  5.       <service name="HelloWCFService.HelloWCFService">  
  6.         <host>  
  7.           <baseAddresses>  
  8.             <add baseAddress="http://localhost:8000/MyService"/>  
  9.           </baseAddresses>  
  10.         </host>  
  11.         <endpoint address="HelloWCFService" binding="wsHttpBinding" contract="HelloWCFService.IHelloWCFService" />  
  12.       </service>  
  13.     </services>      
  14.   </system.serviceModel>  
  15. </configuration>  

这里用了相对地址"HelloWCFService",他会和基地址组合在一起(排在后面)成为终结点的地址,这里也可以指定 为空字符串"",此时基地址(即服务地址)就是终结点的地址,还可以指定一个绝对地址,那样他会覆盖基地址,基地址对这个终结点来说就不起作用了,这里可 以看出,终结点的地址是独立的,可以是基地址的子地址,也可以独立使用另一个地址,他们之间没有必然的链接。

这里的contract 同<service>里面一样,也要使用完全限定名称(带上命名空间)。

注意,在使用IIS承载的时候,必须使用相对地址,也就是终结点必须是基地址的子地址,这是由IIS的部署结构决定的。

 

到这里终结点也配置完成,对应代码的位置找到了吗?

 

接下来是最后一步(或者说两步),配置元数据交换终结点并开启元数据交换行为。这个过程,代码中用了三行,实际上代码这三行仅 仅是添加了元数据交换行为,并没有配置元数据交换终结点,运行时系统为我们自动添加了终结点。这两点缺一不可,虽然系统会为我们添加,我们还是要知道这个 配置的写法。这个很重要。

 

开启元数据交换从原理上应该是两件事,第一是服务允许元数据交换,第二是服务提供元数据交换方式,第一条就是添加元数据交换行 为,表示服务允许这样的请求,第二条就是服务告诉你如何请求,客户端是通过一个固定的终结点去请求的,这个终结点的地址、绑定和协定都是固定的,我们不能 更改,这个是框架的约定,我们只能按要求配置。

 

首先,第一条,允许元数据交换,这个是通过为服务添加一个行为来实现的,行为是用来描述服务的特性的,不同的服务可能有相同的 行为,行为并不是归某服务独有的,因此行为被定义为<system.serviceModel>节的子节,可以被不同的服务引用,他的定义有 些像服务,外面是带s的,里面是不带s的,毕竟可能有许多的行为定义嘛。

先定义个行为:

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.     <services>  
  5.       <service name="HelloWCFService.HelloWCFService">  
  6.         <host>  
  7.           <baseAddresses>  
  8.             <add baseAddress="http://localhost:8000/MyService"/>  
  9.           </baseAddresses>  
  10.         </host>  
  11.         <endpoint address="HelloWCFService" binding="wsHttpBinding" contract="HelloWCFService.IHelloWCFService" />  
  12.       </service>  
  13.     </services>  
  14.     <behaviors>  
  15.       <serviceBehaviors>  
  16.         <behavior name="metaExchange">  
  17.           <serviceMetadata httpGetEnabled="true"/>  
  18.         </behavior>  
  19.       </serviceBehaviors>  
  20.     </behaviors>  
  21.   </system.serviceModel>  
  22. </configuration>  

因为存在服务行为和终结点行为之分,所有<behaviors>和<behavior>之间又套了一 个<serviceBehaviors>,表示这个是服务行为,我们为行为制定了名字,好让<service>可以引用,也可以 不指定,那么所有服务都会应用。交换元数据的行为有固定的标签描述,就是<serviceMetadata>,对着代码看,很熟悉吧。

 

建立了行为以后,要让我们刚才建立的服务去引用他,用<service>的behaviorConfiguration属性:

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.     <services>  
  5.       <service name="HelloWCFService.HelloWCFService"behaviorConfiguration="metaExchange">  
  6.         <host>  
  7.           <baseAddresses>  
  8.             <add baseAddress="http://localhost:8000/MyService"/>  
  9.           </baseAddresses>  
  10.         </host>  
  11.         <endpoint address="HelloWCFService" binding="wsHttpBinding" contract="HelloWCFService.IHelloWCFService" />  
  12.       </service>  
  13.     </services>  
  14.     <behaviors>  
  15.       <serviceBehaviors>  
  16.         <behavior name="metaExchange">  
  17.           <serviceMetadata httpGetEnabled="true"/>  
  18.         </behavior>  
  19.       </serviceBehaviors>  
  20.     </behaviors>  
  21.   </system.serviceModel>  
  22. </configuration>  

 

接下来第二步,建立元数据交换终结点,建立的位置和我们刚才建立的终结点位置相同,但是属性是固定的,大小写都不能写错。

[html] view plain copy
  1. <?xml version="1.0" encoding="utf-8" ?>  
  2. <configuration>  
  3.   <system.serviceModel>  
  4.     <services>  
  5.       <service name="HelloWCFService.HelloWCFService" behaviorConfiguration="metaExchange">  
  6.         <host>  
  7.           <baseAddresses>  
  8.             <add baseAddress="http://localhost:8000/MyService"/>  
  9.           </baseAddresses>  
  10.         </host>  
  11.         <endpoint address="HelloWCFService" binding="wsHttpBinding" contract="HelloWCFService.IHelloWCFService" />  
  12.         <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>  
  13.       </service>  
  14.     </services>  
  15.     <behaviors>  
  16.       <serviceBehaviors>  
  17.         <behavior name="metaExchange">  
  18.           <serviceMetadata httpGetEnabled="true"/>  
  19.         </behavior>  
  20.       </serviceBehaviors>  
  21.     </behaviors>  
  22.   </system.serviceModel>  
  23. </configuration>  


到这里,配置文件就写完了。我们把它放到程序里面去,打开上一篇中建立的服务端程序,为程序添加一个配置文件

右键点击项目->添加->新建项->应用程序配置文件,名字系统会起好(app.config)。把上面的配置写进去,保存。

既然我们已经有了配置文件,就不需要(也不应该)在代码中配置了。代码中的配置会覆盖掉配置文件中的配置。所以我们要对代码修改一下。

main函数中只留下这么几行:

[csharp] view plain copy
  1. ServiceHost host = new ServiceHost(typeof(HelloWCFService));  
  2.   
  3. host.Open();  
  4.   
  5. Console.WriteLine("Service is Ready");  
  6. Console.WriteLine("Press Any Key to Terminate...");  
  7. Console.ReadLine();  
  8.   
  9. host.Close();  

其中,建立SeviceHost 那行被修改了,去掉了baseAddress的参数,但是我们仍需要告诉host 我们要寄存的服务类的类型。

F5运行起来。

然后在浏览器中访问一下服务试试

[html] view plain copy
  1. http://localhost:8000/MyService  


是不是和昨天的结果一样呢。

(CSDN的传图好象挂了哩...)

 

总结一下今天的学习。

我们使用配置文件的方法完成了对WCF服务的配置,从中接触到了服务、终结点和行为的配置方法。配置文件的元素还有许多,像绑 定、安全性等等特性。在今后学到的时候再慢慢展开,配置文件的每一个元素都应该力求背着写下来,一行一行的写,在写的过程中体会,而不是四处复制和粘贴, 这样才能对配置文件的写法有深刻的印象。

 

相关资源

徐长龙老师播讲的《跟我一起从零开始学WCF系列课程》

http://msdn.microsoft.com/zh-cn/hh148206

 

MSDN技术资源库中的WCF参考

http://msdn.microsoft.com/zh-cn/library/dd456779.aspx

转载于:https://www.cnblogs.com/dwuge/p/5315240.html

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

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

相关文章

linux之setsid命令

1 setsid命令 setsid主要是重新创建一个session,子进程从父进程继承了SessionID、进程组ID和打开的终端,子进程如果要脱离父进程&#xff0c;不受父进程控制&#xff0c;我们可以用这个setsid命令 2 测试 比如我们ping baidu.com setsid ping baidu.com 这个时候我们再ctrl…

【ArcGIS遇上Python】三种利用Python批量处理地理数据的方法——以栅格数据投影转换为例

时至今日,笔者已经总结了三种用Python语言结合ArcGIS10.x提供的接口去批量处理地理空间数据的方法。即: 1. 用IDLE、Python Tools for Visual Studio等去编写独立的py脚本文件; 2. 用Python提供的tKinter模块去构建可视化窗体,并将其打包成exe可执行文件; …

【深入JAVA】java注解

在阅读的过程中有不论什么问题&#xff0c;欢迎一起交流 邮箱&#xff1a;1494713801qq.com QQ&#xff1a;1494713801 1、什么是java注解 注解&#xff0c;顾名思义&#xff0c;注解,就是对某一事物进行加入凝视说明&#xff0c;会存放一些信息。这些信息可能对以后某…

vlan跨交换机 udp广播_【详解】VLAN和VXLAN有何区别?VXLAN运用场景有哪些?

随着网络技术的发展&#xff0c;云计算凭借其系统利用率高、人力/管理成本低以及灵活性/扩展性方面展现的优势&#xff0c;已经成为目前各大行业IT建设的新趋势。而服务器的虚拟化作为云计算的核心技术之一&#xff0c;也得到了越来越多的应用&#xff0c;从而极大的增加了数据…

linux tcp 内核模块,C – Linux – 内核模块 – TCP头

我正在尝试创建linux内核模块,它将检查传入的数据包.目前,我正在提取数据包的TCP标头并读取源和目标端口 – >但是我得到的值不正确.我有钩功能&#xff1a;unsigned int hook_func(unsigned int hooknum,struct sk_buff *skb,const struct net_device *in,const struct net…

C#11:原始字符串

这一直以来是我写代码的一个痛点&#xff0c;C#11终于解决了&#xff0c;那就是我想把一个整齐的格式的json字符串转出&#xff0c;但不能如愿&#xff0c;要不用一个三方库来搞定&#xff0c;要不就加各种双引号&#xff0c;如果有变量还得小心处理{}&#xff0c;因为在C#stri…

php in_array 判断数组中是否存在此元素

判断数组中是否存在此元素在php中很简单&#xff0c;直接使用 in_array即可。用法如下 &#xff1a; <?php $array_1array(red,blue,green); if(in_array(red1, $array_1)){echo 1; }else{echo 2; }以上例子我新建了一个数组array_1&#xff0c;里面的值想必也看到了。…

Android开源项目SlidingMenu本学习笔记(两)

我们已经出台SlidingMenu使用&#xff1a;Android开源项目SlidingMenu本学习笔记&#xff08;一个&#xff09;&#xff0c;接下来再深入学习下。依据滑出项的Menu切换到相应的页面 文件夹结构&#xff1a; 点击Bluetooth能够切换到对应的界面 关键代码 MainActivity.java pack…

Makefile的学习

1 Makefile 就这样理解&#xff0c;帮我们对程序进行编译&#xff0c;我们每次gcc g啥的很麻烦 2 举例子 我这里有3个文件first.c second.c third.c first.c文件如下 #include <stdio.h> int add(int a, int b) {return a; } second.c文件如下 int sub(int a, int …

扒开系统调用的三层皮(下)

5234 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 1.给MenuOS增加time和time-asm命令 步骤 rm menu -rf //强制删除git clonehttp://github.com/menging/menu.git // 克隆相关信息到menucd menumake rootfs //自动编…

Python版九九乘法表

1、示例一 >>> for i in range(10):s=for j in range(1,i+1):s+=str(j)+*+str(i)+=+str(j*i)+\tprint s 2、示例二 >>> for i in range(10):s=for j in range(1,i+1):s+=str(j)+*+str(i)+=+repr(j*i).ljust(4)print s 3、示例三 >>> for i in ran…

R 语言 相关入门资料

《R语言基础语法入门》&#xff1a; http://www.xueqing.tv/upload/april-training/day1/index.html#1 转载于:https://www.cnblogs.com/pinganzi/p/7354679.html

Tiny之Web工程构建

友情提醒&#xff1a;阅读此文需要java、Maven环境搭建技能&#xff0c;关于java开发环境及maven环境搭建请咨询谷哥和度娘。 搭建TinyWeb工程环境 搭建一下TinyWeb的开发环境&#xff0c;是非常简单的 如果你没有下载过Tiny框架&#xff0c;请在命令行中输入下面的命令&…

linux 端口 流量统计,Linux下如何对端口流量进行统计

在不修改源代码的情况下对程序暴露端口流量进行监控统计&#xff0c;可以利用Linux中自带的Iptable添加简单的规则让其起到端口流量统计的作用。但是需要注意的是在服务器重启、Iptable服务重启的时候统计数据会被重置清零。添加需要统计的端口1、输入监控下面示例是监控目标端…

Hello Playwright:(1)从开发到部署

前言虽然前面写过几篇 C# 使用 Playwright 的文章&#xff0c;但是讲解的不太全面。看到有朋友有学习这方面的需要&#xff1a;因此&#xff0c;就有了《Hello Playwright》这个系列的产生。Playwright 介绍Playwright 是微软开源的一个基于 Node.js 的工具库&#xff0c;可使用…

没有主清单属性_原神:晴知的主C诺艾尔大型进阶攻略初版

作者&#xff1a;NGA-最可爱的晴知前言大家好我是晴知&#xff0c;一个诺艾尔主C玩家(目前是0命座)&#xff0c;截至10月8日&#xff0c;我的账号等级为41级&#xff0c;深境螺旋11层打通&#xff0c;但星数不够12层&#xff0c;一者因为圣遗物太烂而我想45级再刷圣遗物&#x…

【ArcGIS风暴】ArcGIS栅格数据(分区)统计方法总结

【问题描述】如图所示,如何根据中国植被区划分区,统计各个区域内NDVI的平均值? 目录 1、Layer Properties 2、Zonal Statistics as Table 3、Band Collection Statistics 分区统计及根据统计区域或赋值栅格为每个区域计算统计数据。分区统计包括众数、最大值、均值、中位…

剑指offer之反转链表

1 问题 反转链表&#xff0c;比如0->1->2->3反转后变成了3->2->1->0 2 分析 搞3个指针&#xff0c;初始化一个指针&#xff0c;让头结点指向这里&#xff0c;然后另外一个指针初始化为NULL&#xff0c;然后让第一个节点指向这里&#xff0c;然后头结点依次…

php str_replace 字符串替换

我们在这里使用 str_replace 来替换一串字符串中的字符&#xff0c;例如如下代码&#xff1a; <?php $strHello world!; $str1str_replace("world","Terry",$str); echo $str1; str的值为Hello world!&#xff0c;我们在str_replace后面第一个参数是…

python去掉字符串中空格的方法

1.strip()&#xff1a;把头和尾的空格去掉 2.lstrip()&#xff1a;把左边的空格去掉 3.rstrip()&#xff1a;把右边的空格去掉 4.replace(c1,c2)&#xff1a;把字符串里的c1替换成c2。故可以用replace( ,)来去掉字符串里的所有空格 5.split()&#xff1a;通过指定分隔符对字符串…