初识WCF2

参照:

http://blog.csdn.net/songyefei/article/details/7371571

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

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel;
using System.ServiceModel.Description;

namespace HelloWCFService
{
    class Program
    {
        static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8000/MyService");

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

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

            ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
            smb.HttpGetEnabled = true;
            host.Description.Behaviors.Add(smb);

            host.Open();

            Console.WriteLine("Service is Ready");
            Console.WriteLine("Press Any Key to Terminate...");
            Console.ReadLine();

            host.Close();

        }
    }

    [ServiceContract]
    interface IHelloWCFService
    {
        [OperationContract]
        string HelloWCF();
    }

    public class HelloWCFService : IHelloWCFService
    {
        public string HelloWCF()
        {
            return "Hello WCF!";
        }
    }
}

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

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

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

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

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

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

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

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

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

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

建立基地址:

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

建立服务:

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

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

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

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

    ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
    smb.HttpGetEnabled = true;
    host.Description.Behaviors.Add(smb);  

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

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

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

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

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>  

      </system.serviceModel>
    </configuration>  

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

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <services>
          <service>
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8000/MyService"/>
              </baseAddresses>
            </host>
          </service>
        </services>
      </system.serviceModel>
    </configuration>  

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

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

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <services>
          <service name="HelloWCFService.HelloWCFService">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8000/MyService"/>
              </baseAddresses>
            </host>
          </service>
        </services>
      </system.serviceModel>
    </configuration>  

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

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

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

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <services>
          <service name="HelloWCFService.HelloWCFService">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8000/MyService"/>
              </baseAddresses>
            </host>
            <endpoint address="HelloWCFService" binding="wsHttpBinding" contract="HelloWCFService.IHelloWCFService" />
          </service>
        </services>
      </system.serviceModel>
    </configuration>  

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

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

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

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

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

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

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

先定义个行为:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <services>
          <service name="HelloWCFService.HelloWCFService">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8000/MyService"/>
              </baseAddresses>
            </host>
            <endpoint address="HelloWCFService" binding="wsHttpBinding" contract="HelloWCFService.IHelloWCFService" />
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="metaExchange">
              <serviceMetadata httpGetEnabled="true"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>  

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

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

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="HelloWCFService.HelloWCFService"behaviorConfiguration="metaExchange">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/MyService"/>
          </baseAddresses>
        </host>
        <endpoint address="HelloWCFService" binding="wsHttpBinding" contract="HelloWCFService.IHelloWCFService" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="metaExchange">
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

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

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <services>
          <service name="HelloWCFService.HelloWCFService" behaviorConfiguration="metaExchange">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8000/MyService"/>
              </baseAddresses>
            </host>
            <endpoint address="HelloWCFService" binding="wsHttpBinding" contract="HelloWCFService.IHelloWCFService" />
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="metaExchange">
              <serviceMetadata httpGetEnabled="true"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>  

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

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

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

ServiceHost host = new ServiceHost(typeof(HelloWCFService));  

host.Open();  

Console.WriteLine("Service is Ready");
Console.WriteLine("Press Any Key to Terminate...");
Console.ReadLine();  

host.Close(); 

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

F5运行起来。

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

http://localhost:8000/MyService  

总结一下今天的学习。

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

时间: 2024-10-12 18:03:18

初识WCF2的相关文章

初识Python,望君多多关照

在学习Python之前,我们接触过数据结构和网页制作.前者让我们学习如何把C语言运用的更加整齐规范,而后者让我们亲身学习如何运用所学,制作一个静态网页.通过这些课程的学习,让我对C语言产生了比较大的压力,以至于对编程.对这学期的Python课程都有一种如临大敌的感觉. 但是真的学习了这门课程,体会了编码过程中的一些固定运用方法和套路之后,也许过程中对这门课程隐隐约约产生了一点点朦胧的感觉,仿佛他也并没有想象中的那么困难,起码现在的学习让我认为,他可能没有C语言那么繁琐和麻烦.当然,以一个初学者的

初识数组排序!!!!

<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>初识数组排序</title> <!--调试成功--> <style type="text/css"> *{ padding:0; margin: 0; } li,ul{ list-style: none; } #p

初识操作系统和linux

初识操作系统和linux 1.计算机系统由硬件系统和软件系统两大部分组成:是一种能接收和存储信息,并按照存储在其内部的程序对海量数据进行自动.高速地处理,然后把处理结果输出的现代化智能电子设备. 2.世界上第一台计算机是1946年诞生在美国宾州大学. 3.冯·诺依曼体系结构:1946年数学家冯·诺依曼于提出计算机硬件系统由运算器.控制器.存储器.输入设备.输出设备.摩根定律:当价格不变时,集成电路上可容纳的元器件的数目,约每隔18-24个月便会增加一倍,性能也将提升一倍.现在计算机技术进本很难遵

JAVA 初识类加载机制 第13节

JAVA 初识类加载机制 第13节 从这章开始,我们就进入虚拟机类加载机制的学习了.那么什么是类加载呢?当我们写完一个Java类的时候,并不是直接就可以运行的,它还要编译成.class文件,再由虚拟机解释给当前的操作系统去执行.这些过程都是我们看不见的,我们能看见的也就是一个.class文件.既然虚拟机要解释这些.class文件给当前的操作系统听,那么他怎么获得这些.class文件呢?虚拟机获得这些.class文件的过程就是类加载了. 所以,总结来说就是:虚拟机将.class文件从磁盘或者其他地

初识React

原文地址:北云软件-初识React 专注于UI 在MVC分层设计模式中,react常被拿来实现视图层(V).React不依赖于技术栈的其他部分,因此可以方便的在现有项目中尝试用它来实现一个小特性. 虚拟DOM React从DOM中抽象出来,给出一种更简洁的编程模型,且性能表现更好.能够通过NodeJS实现服务端渲染,通过React Native开发原生app. 数据流React实现单向.响应式数据流,减少boilerplate且比传统数据绑定更容易理解. 简洁的组件React的组件都实现了一个r

泛型的几种类型以及初识webform

今天学习的可以分为两类吧,但是学习的都是比较抽象的,不太容易掌握吧.首先我们大部分时间学习了泛型,泛型的委托,泛型接口以及枚举器,迭代器,扩展方法:最后简单的认识了webform,实现了一个简单的功能. 一.泛型 定义:泛型(generic)可以软糖多个类型共享一组代码,泛型允许我们声明类型参数化.可以用不同的类型进行实例化,说白了,就是可以用类型占位符,创建具体类型致命的真实概念.C#中提供了五种泛型,类,结构,接口,委托和方法.下面举例说明可能更容易理解, class MyStack<T>

最新计算机技术与管理科学应用专家——初识ERB

ERB管理系统:英文全称Enterprise Resource and Behavior,英文简称:ERB,中文名全称:企业资源与行为管理系统.ERB是由理文企业管理顾问有限公司首席管理师,现任商翼ERB企业管理系统项目总监吴志华先生,于2010年9月首先提出的.ERB不再单以供应链管理作为系统应用的基础,而是以企业行为与企业资源规划的最佳结合作为系统应用设计的核心基础,强调企业行为的规划.执行.监督与追溯,强调企业管理水平与员工素养的持续提升:提供企业行为与企业资源管理最佳结合的整体应用解决方

[OpenGL]环境搭建以及OpenGL初识

想往游戏行业发展的话,经常被提及到的就是OpenGL和DirectX,这两者听起来感觉是一门挺高深的技术,今天我也开始摸索学习OpenGL,那么OpenGL到底是什么?它和DirectX有什么区别和联系? OpenGL初识 OpenGL只是一套图形函数库 DirectX包含图形.声音.输入.网络等模块. 但就图形而论,DirectX的图形库性能不如OpenGL,OpenGL稳定,可以跨平台使用,DirectX只支持Windows平台,所以OpenGL还是有它的优势!OpenGL ES是OpenG

初识git

初识git 1 安装git 最早Git是在Linux上开发的,很长一段时间内,Git也只能在Linux和Unix系统上跑.不过,慢慢地有人把它移植到了Windows上.现在,Git可以在Linux.Unix.Mac和Windows这几大平台上正常运行了. 要使用Git,第一步当然是安装Git了.根据你当前使用的平台来阅读下面的文字: 1.1 在Linux上安装Git 首先,你可以试着输入git,看看系统有没有安装Git: ``` $ git The program 'git' is curren