4. 通过配置文件方式实现基于 WCF 服务的 HelloWorld 实例

契约与元数据

  • WCF 技术与其他分布式技术最显著的区别是耦合性是基于契约的,不是基于代码的耦合,因为在契约中不包含具体的逻辑,所以为我们构建松耦合的分布式应用程序提供了良好的基础。
  • Web Service Description Language(WSDL)
    Web Service 的描述语言 WSDL 里面包含了下面 5 个内容,这 5 个内容是我们在进行数据通信的时候必需的内容:
    • 互操作契约(Contract)
    • 描述服务与相应的 Endpoint 端点
    • Binding 绑定
    • 消息和类型的定义
    • 策略
      在进行消息传递的时候,要应用哪些具体的策略,都是由 WSDL 来进行描述的。
  • 契约与元数据用于生成客户端的代理和配置

服务描述和元数据

  1. 生成服务描述
    如图 1,在 ServiceHost 里面运行着服务以及相应的端点,ServiceHost 里面又多了一个东西是 ServiceDescription 服务描述,也就是 Service 具体的描述,由这个 ServiceDescription 将 Service 和 Endpoint 以及相关的 Address、Binding、Contract 信息在这里进行了相应的记录,外面是有一个 Config 文件,当 ServiceHost 启动的时候来加载这个 Config 文件,根据 Config 文件里面具体的内容来生成相应的描述信息。

    图 1

  2. 生成 WSDL
    如图 2,由 ServiceDescription 服务描述来生成 WSDL 的文件,通过 svcutil.exe 这个工具来生成相应的在客户端所使用的这个 Proxy 代理以及相应的代码,同样在客户端我们可以通过 Config 配置文件的方式来影响 Proxy 代理以及 Channel 通道的生成。

    图 2

  3. 元数据的交换
    完成了图 2 阶段后,我们可以通过 svcutil.exe 这个工具来实现从 Service 服务这一端到 Client 客户这一端的数据交换,整个的服务描述与数据的交互就是图 3 的结构,从这个结构图我们可以看到,Client 客户端在获取 Service 服务具体的信息的时候,实际上不会直接与 Service 或者 Endpoint 来进行接触,它是通过 ServiceDescription 服务描述来获得的并且通过元数据交互这种方式来得到相应的信息,然后构建客户端自己的 Proxy 代理。所以,如果我们的 Service 或者 Endpoint 内部的一些逻辑发生变化的话,只要它不影响 ServiceDescription 服务描述,就不会对客户端的 proxy 代理产生影响,也就不会对客户端产生影响。通过这种方式实现了 Client 端和 ServiceHost 端的松耦合关系。

    图 3

通过配置文件方式实现基于 WCF 服务的 HelloWorld 实例

服务相应的代码除了可以通过编码的方式实现的,还可以通过向导来生成。以下操作基于《3. 通过编码方式实现基于 WCF 服务的 HelloWorld 实例》一文中的项目代码。

1. 服务端配置 App.config

在 Host 工程右击 Add -> New Item选择 Application Configuration File,新建一个 App.config 配置文件。

配置文件解释:

  • Service的配置 (<service/>节点)
    • 在<services/>里我们添加了一个<service/>,这个service的名称就是我们前面实现的服务的名称,格式 name="HelloWorldService.HelloWorldService",就是我们的命名空间+具体实现服务的名称。behaviorConfiguration="serviceBehavior",表示它服务的行为配置采用 serviceBehavior 这个策略
    • 我们看到暴露出了两个端点出来,这两个端点都是绑定Http协议,但是还是有区别的。上面的端点采用基本的 Http 进行绑定,基于 basicHttpBinding 的端点它所绑定的契约就是 Service 中定义的 HelloWorldService.IHelloWorldService 这个契约。下面的端点使用mexHttp 进行绑定,这个mex是WCF里用于元数据交互的一种特有方式,在我们进行元数据交换的时候,指定了由WCF内建的一个接口 IMetadataExchange,这个接口的主要作用就是来完成元数据的交换,并且在后面指定了这个端点具体的地址 "mex"。
    • 在<endpoint/>这个节点描述完毕以后,然后就是<Host/>节点,这个service 它所运行在的 Host,在 Host 里面主要描述了一个基本的地址就是"http://localhost:8000",所以对于 HelloWorldService 这个服务真实的地址是 "http://localhost:8000/HelloWorldService",那么一样元数据交换的地址是"http://localhost:8000/mex"
  • Service 行为配置(<behaviors/>节点)
    在<behaviors/>里我们可以指定服务具体的行为,<serviceMetadata httpGetEnabled="true"/> 是说服务的元数据是否能用Http协议Get出来,也就是说当我们应用了这个配置选项以后,元数据我们是允许Get方法操作的
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="HelloWorldService.HelloWorldService" behaviorConfiguration="serviceBehavior">
        <endpoint address="HelloWorldService" binding="basicHttpBinding" contract="HelloWorldService.IHelloWorldService" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="serviceBehavior">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>  
</configuration>

2.通过元数据生成代理和配置文件

2.1 保存 Host 这端的配置文件,启动 Host:

注意:HTTP 无法注册 URL http://+:8000/。进程不具有此命名空间的访问权限(有关详细信息,请参见 http://go.microsoft.com/fwlink/?LinkId=70353)。
如按照例子一开始就遇到这样的问题,原因可能是Win 7,解决方法是Visual Studio 以管理员的身份运行就可以了。

  • 由于刚才我们在配置文件中已经指明了使用Http协议这么一个服务以及8000它相应的端口,因此在浏览器我们可以通过输入 http://localhost:8000/ 来看到和这个服务相关的具体内容如图 1 。我们可以通过其中提供的 svcutil.exe 工具,单机 http://localhost:8000/?WSDL 看到具体的描述信息在客户端生成相应的Proxy代码,对个这个WSDL配置文件当中,我们可以看到我们指定的一些信息,像我们使用什么样的协议进行传递等这些信息都在WSDL里面进行了非常详细的描述。
图1:host启动
  • 如图 2,我们已在Host这一端添加了相应的配置文件使得Host不但能够对外提供基于 Tcp 协议位置在localhost端口在9000下的服务。同时在上回通过编码实现中也提供了基于 Http 协议位置在 localhost 端口在8000下的服务。那么我们对比这两个服务的话,通过写代码所作的这些事情事实上我们可以通过配置文件的方式来完成,这也就意味着我们在 Host 这一端希望对外提供一个服务的时候其实对于这个服务而言是不需要编写任何的代码,我们需要做的是在配置文件当中来完成对这个服务的配置。


    图 2:WSDL
2.2 客户端添加服务引用,自动生成配置文件与代码

在 Client 工程上右击 Add Service Reference,在 Address 栏输入已经开启的服务地址 http://localhost:8000/,点击 Go ,将命名空间改为 Proxy,点击 OK 就添加成功了。

image.png

上述步骤提供了基于Http协议消息的 Host,由Visual Studio会根据WSDL里面的内容来自动生成相应的代理文件以及相应的配置文件。Project -> Show All Files可以看到如下目录。在Reference.svcmap下面有个Reference.cs,在这个Reference.cs里面有由系统自动为我们生成的代理类,在我们进行使用的时候,我们直接使用代理类来进行服务的操作。


image.png

在 Client 端生成了和 Host 端相关的的相应的配置文件以及里面的配置信息和配置参数,对于这些参数可以根据我们具体需求来进行具体的配置如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_IHelloWorldService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
                  <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
                  <security mode="None">
                    <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
                    <message clientCredentialType="UserName" algorithmSuite="Default"/>
                  </security>
                </binding>
            </basicHttpBinding>
          
            <!--<netTcpBinding>
                <binding name="NetTcpBinding_IHelloWorldService" />
            </netTcpBinding>-->
        </bindings>
        <client>
            <endpoint address="http://localhost:8000/HelloWorldService" binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_IHelloWorldService"
                contract="Proxy.IHelloWorldService" name="BasicHttpBinding_IHelloWorldService" />
            <!--<endpoint address="net.tcp://localhost:9000/HelloWorldService"
                binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IHelloWorldService"
                contract="Proxy.IHelloWorldService" name="NetTcpBinding_IHelloWorldService">
            </endpoint>-->
        </client>
    </system.serviceModel>
</configuration>
2.3 客户端调用服务

由于说Client端系统已经为我们生成好了和这个IHelloWorldService契约相关的 Proxy 代码了,因此我们自己手动的代码就不需要了,然后对于 Proxy 的使用我们就不需要对通过 CreateChannel 这种方式来进行调用,我们可以直接 Proxy.HelloWorldServiceClient proxy = new Proxy.HelloWorldServiceClient();,通过实例化对象的方式来实例化一个新的Proxyl对象出来就可以了,那我们实例化出来的这个 proxy 这个对象就自动包含了契约相关的信息,在 Proxy 生成以后我可以调用相应的方法来完成相应的任务,这样就实现了基于Http协议的分布式调用。在 WCF 当中无论是我们使用基于http协议的消息的传递还是使用基于 Tcp 协议的消息传递都是遵循同一个模型来开发的,如果说我们开发了一个复杂系统在原来是使用 Tcp 协议来进行数据传递的,然而在实际部署过程中要改变成Http协议,那么我们可以通过配置的方式修改一些参数就能够项目从使用Tcp协议移植到使用 Http 协议上面。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,681评论 6 517
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 95,205评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 169,421评论 0 362
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 60,114评论 1 300
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 69,116评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,713评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,170评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,116评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,651评论 1 320
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,714评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,865评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,527评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,211评论 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,699评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,814评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,299评论 3 379
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,870评论 2 361

推荐阅读更多精彩内容