(转)[老老实实学WCF] 第二篇 配置WCF

时间:2022-09-24 16:07:47

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

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

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

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

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

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

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

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

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

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

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

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

建立基地址:

  1. Uri baseAddress = new Uri("http://localhost:8000/MyService");

建立服务:

  1. ServiceHost host = new ServiceHost(typeof(HelloWCFService), baseAddress);

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

  1. host.AddServiceEndpoint(typeof(IHelloWCFService), new WSHttpBinding(), "HelloWCFService");

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

  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>,所以配置文件中至少先应该是这个样子:

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3. <system.serviceModel>
  4. </system.serviceModel>
  5. </configuration>

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

晕了么...慢慢来。

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

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

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

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3. <system.serviceModel>
  4. <services>
  5. <service>
  6. </service>
  7. </services>
  8. </system.serviceModel>
  9. </configuration>

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

  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属性,指定的时候后要用完全限定名(带着命名空间)

  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>的子节,毕竟他是属于服务的嘛。

  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的,毕竟可能有许多的行为定义嘛。

先定义个行为:

  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属性:

  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>

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

  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函数中只留下这么几行:

  1. ServiceHost host = new ServiceHost(typeof(HelloWCFService));
  2. host.Open();
  3. Console.WriteLine("Service is Ready");
  4. Console.WriteLine("Press Any Key to Terminate...");
  5. Console.ReadLine();
  6. host.Close();

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

F5运行起来。

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

  1. http://localhost:8000/MyService

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

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

总结一下今天的学习。

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

(转)[老老实实学WCF] 第二篇 配置WCF的更多相关文章

  1. &lbrack;老老实实学WCF&rsqb; 第二篇 配置WCF

    老老实实学WCF 第二篇 配置WCF 在上一篇中,我们在一个控制台应用程序中编写了一个简单的WCF服务并承载了它.先回顾一下服务端的代码: using System; using System.Col ...

  2. 老老实实学习WCF&lbrack;第二篇&rsqb; 配置wcf

    老老实实学WCF 第二篇 配置WCF 在上一篇中,我们在一个控制台应用程序中编写了一个简单的WCF服务并承载了它.先回顾一下服务端的代码: using System; using System.Col ...

  3. (转)&lbrack;老老实实学WCF&rsqb; 第二篇 配置WCF

    第二篇 配置WCF 在上一篇中,我们在一个控制台应用程序中编写了一个简单的WCF服务并承载了它.先回顾一下服务端的代码: using System; using System.Collections. ...

  4. 第二篇 配置wcf

    老老实实学WCF 第二篇 配置WCF 在上一篇中,我们在一个控制台应用程序中编写了一个简单的WCF服务并承载了它.先回顾一下服务端的代码: using System; using System.Col ...

  5. 跟我学PHP第二篇- 配置Mysql以及PHP WampServer篇(1)

    大家好,昨天我给大家介绍了如何去安装ZEND STUDIO,下面昨天文章的链接: http://www.cnblogs.com/kmsfan/p/zendStudio.html 本节为配置的第一部分, ...

  6. 小白学Maven第二篇配置Ecilpse

    Maven:里面提到了一个很重要的概念:*仓库,本地仓库,私服: *仓库:是Maven通过一个地址索引去(http://mvnrepository.com/)下载需要的架包: 本地仓库:是Mave ...

  7. &lpar;转&rpar;&lbrack;老老实实学WCF&rsqb; 第一篇 Hello WCF

    http://blog.csdn.net/songyefei/article/details/7363296#comments 老老实实学WCF  第一篇 Hello WCF WCF(Windows ...

  8. &lbrack;老老实实学WCF&rsqb; 第一篇 Hello WCF

    老老实实学WCF  第一篇 Hello WCF WCF(Windows Communication Foundation)是微软公司推出的面向服务技术的集大成者,涵盖继承了其之前发布的所有的分布式应用 ...

  9. 老老实实学WCF&lbrack;第一篇&rsqb; Hell wcf

    老老实实学WCF  第一篇 Hello WCF WCF(Windows Communication Foundation)是微软公司推出的面向服务技术的集大成者,涵盖继承了其之前发布的所有的分布式应用 ...

随机推荐

  1. js中使用new Date&lpar;str&rpar;创建时间对象不兼容firefox和ie的解决方式

    /** * 解决 ie,火狐浏览器不兼容new Date(s) * @param strDate * 返回 date对象 * add by zyf at 2015年11月5日 */ function ...

  2. FFT时域与频域的关系,以及采样速率与采样点的影响

    首先对于FFT来说,输入的信号是一个按一定采样频率获得的信号序列,而输出是每个采样点对应的频率的幅度(能量). 下面详细分析: 在FFT的输出数据中,第一个值是直流分量的振幅(这样对应周期有无穷的可能 ...

  3. AJAX发送参数到后台,前台火狐debug报undefine

    后面经过查找:估计是数据并不是Json格式,由于var PATIENT_ID=getIdSelections();其中PATIENT_ID是数组,所以必须转成字符串. $('#table').on(' ...

  4. php反射机制

    PHP5添加了一项新的功能:Reflection.这个功能使得phper可以reverse-engineer class, interface,function,method and extensio ...

  5. Liferay 6&period;2 改造系列之二十四:修改liferay密码的加密方式

    为了便于后期与Cas集成过程中使用数据库用户的方便,将liferay密码的加密方式改为SHA. 在/portal-master/portal-impl/src/portal.properties配置文 ...

  6. 刨根问底U3D---如何退出Play模式后保留数据更改

    实际中遇到的需求 在做一款对抗类游戏,目前正在调整游戏的平衡性 所以就产生了一个需求 希望可以在Play模式时候对数据源做的更改可以在退出时候被保存下来. 举个Case, 比如 有一个炮塔 可以发射子 ...

  7. WinStore之Application Data

    一.Application Data简介 Applicaion Data相当于桌面应用的注册表,存储一些用户配置信息,如运行时状态,用户喜好等,需要注意的时,当卸载应用时,这些数据会被删除,所以不要存 ...

  8. it小小鸟心得

    本来打算就这么浑浑噩噩的过完我的大学四年生涯,但当我读完这本书,改变了我的想法.许多人说大学是最美好的,确实,在这里,我每天都不用认真听讲,不用准时去上课,可是久而久之,自己有感而发觉得这样碌碌无为下 ...

  9. servlet以及HTML中路径问题

    路径问题: ①相对路径和绝对路径: 绝对路径:绝对路径是以/开头的路径! 相对于当前服务器的绝对路径:如果是服务器解析,那么/就代表当前服务器的绝对路径:http://localhost:8080 相 ...

  10. bash 基础命令

    bash的基础特性(): () 命令历史 history 环境变量: HISTSIZE:命令历史记录的条数: HISTFILE:~/.bash_history: HISTFILESIZE:命令历史文件 ...