初识WCF(一)

一, WCF简介

WCF即是Windows Communication Foundation的缩写,是由微软发展的一组数据通信的应用程序开发接口,从一定程度上说,WCF是微软在Web Service技术规范下实现的一种用于在分布式环境下进行数据通信的一个框架(asp.net Web Service也是在web service规范下实现的一个用于在分布式环境下进行数据通信的一个技术框架, WCF可以说是asp.net web service的高级版本).

WCF服务来通过通信双方的Contract(契约)来实现实现数据通信, Contract(契约)约定了WCF服务所提供的功能.Contract(契约)是以接口的方式来得以体现的.Contract(契约)有四种类型,即:

ServiceContract, 服务契约,  约定服务的定义

OperationContract, 操作契约, 约定服务提供的方法

DataContract, 数据契约, 约定通信双方通信时的数据格式

MessageContract, 消息契约, 约定在通信期间改写消息内容的规范

WCF服务并不能单独存在,它必须寄宿于一个运行着的进程中才能够提供服务. 承载WCF服务的进程成为宿主,为服务指定宿主的过程叫着服务寄宿(service hosting).

服务寄宿有两种方式:自我寄宿(self-hosting)和IIS寄宿. 自我寄宿,即是将服务寄宿在一个运行着的控制台程序的进程中,IIS寄宿则是降服务寄宿与IIS的工作进程中.

服务以一个特殊的对象ServiceHost来实现寄宿.

二, 创建WCF程序

本段程序实现一个提供基本的加减乘除运算的通信框架. 如上所诉, WCF服务是用契约来保证通信的. 因此创建WCF的第一步就是来设计契约.

1, 首先建立一个空白解决方案WCFService, 包含5个项目Contracts, Services, SelfHosting, IISHosting, Clients.

Constracts和Services为类库项目, 分别为约定契约和实现契约的服务.

SelfHosting为控制台应用程序, 用来实现自我寄宿

IISHosting为WCF项目或者Web Application项目, 用来实现IIS寄宿.本例中为WCF项目

Clients为客户端,在本例中为控制台应用程序, 用来调用WCF服务.

解决方案的结构如下:

2, 定义服务契约,服务契约使用接口(interface)来实现的,并且需要通过ServiceContractAttribute这个特性来标记.接口中定义的方法用OperationContractAttribute来标记.

using System.ServiceModel;

namespace WCFService.Contracts
{
    [ServiceContract(Name="WCFServiceContract",Namespace="http://www.woniugu.com")]
    public interface ICaculatorService
    {
        [OperationContract]
        double Add(double x, double y);
        [OperationContract]
        double Minus(double x, double y);
        [OperationContract]
        double Multiply(double x, double y);
        [OperationContract]
        double Divide(double x, double y);
    }
}

3,定义好服务契约之后,需要通过实现服务契约来创建真正的WCF服务

using WCFService.Contracts;

namespace WCFService.Services
{
    public class CaculatorService : ICaculatorService
    {
        public double Add(double x,double y)
        {
            return x + y;
        }
        public double Minus(double x ,double y){
            return x-y;
        }
        public double Multiply(double  x,double y){
            return x*y;
        }
        public double Divide(double x, double y) { 
            try{
                return x / y;
            }catch{
                return 0;
            }
        }
    }
}

4.实现服务的Self-Hosting(自我寄宿)

WCF服务必须依赖于一个运行这的进程,这个进程称为宿主.为了实现自我寄宿,我们这里创建了一个控制台应用程序,并且通过创建一个ServiceHost对象,并且添加EndPoint(终结点)来实现寄宿.我们可以在代码中直接添加终结点,也可以通过添加应用程序配置文件来添加终结点.在实际的项目中,我们一般采取配置文件的方式,因为配置文件更改之后不需要编译代码,可以随时通过添加终结点来对WCF服务进行扩展.

下面首先来看配置文件的方式.配置文件如果要手动编码起来很麻烦而且容易出错,visual studio提供了一个 编辑WCF配置文件的工具,选择 工具--WCF服务配置编辑器 后打开SelfHosting项目下的app.config文件,选择添加服务,一步步操作下来即可.

先看配置文件.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <services>
            <service behaviorConfiguration="MetadataBehavior" name="WCFService.Services.CaculatorService">
                <endpoint address="http://localhost:9999/CaculatorService" binding="wsHttpBinding"
                    name="CaculatorService" contract="WCFService.Contracts.ICaculatorService" />
            </service>
        </services>
        <behaviors>
            <serviceBehaviors>
                <behavior name="MetadataBehavior">
                    <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:9999/CaculatorService/Metadata" />
                </behavior>
            </serviceBehaviors>
        </behaviors>
    </system.serviceModel>
</configuration>

通过创建ServiceHost对象来实现自我寄宿

using System;
using System.ServiceModel;
using WCFService.Services;

namespace WCFService.SelfHosting
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(typeof(CaculatorService)))
            {
                host.Opened += delegate
                {
                    Console.WriteLine("服务已启动,按任意键终止服务...");
                };
                host.Open();
                Console.ReadKey();
            }
        }
    }
}

EndPoint(终结点)在WCF中是个非常重要的概念,通过终结点来实现通信.WCF通过终结点来将服务暴露给Client, 由于客户端与服务之间的通信是基于EndPoint(终结点)的,因此我们需要为客户端也配置终结点, 客户端通过终结点来调用与之相匹配的服务. 当Server(服务)成功寄宿以后, 会监听来自客户端的请求, 只有Client的EndPoint(终结点)与之Server的某个EndPoint相匹配时,这个请求才能被监听到(服务端可以为一个服务指定多个终结点). 简单的说, 就是只有客户端有与服务端相匹配的EndPoint的时候,我们才可以调用这个服务. 这个匹配是非常严格的,不但要求EndPoint的URI要相同,终结点的Headers等信息也要相同,对于Binding,一般只有客户端和服务端的一致才能够进行通信.

终结点包含4个很重要的对象:Address, Binding,Contract, 可以很简记为ABC,还有Behavior.

Address对象, 通过一个URI来唯一标记此终结点,该对象最重要的目的就是约定client(客户端)如何找到此终结点.

Binding对象, 实现通信的所有底层细节,比如此服务采用什么样的通信协议,是http还是tcp还是其他. 通信的消息采用什么样的编码, 是text/XML,还是binary还是其他.

Contract对象, 指定与此终结点对应的Contract(契约).即我们需要暴露给客户端的服务.

Behavior对象, Behavior的主要作用是定制Endpoint在运行时的一些必要的Behavior。比如Service 回调Client的Timeout;Client采用的Credential type;以及是否支持Transaction等.

<services>
     <service behaviorConfiguration="MetadataBehavior" name="WCFService.Services.CaculatorService">
     <endpoint address="http://localhost:9999/CaculatorService" binding="wsHttpBinding"
         name="CaculatorService" contract="WCFService.Contracts.ICaculatorService" />
     </service>
</services>      

配置文件中的这部分便是为WCF服务指定终结点的配置.

至此,我们已经实现了WCF服务的寄宿.现在我们把宿主程序SelfHosting.exe运行起来看看.

5.接下来,就应该实现客户端的调用了,我们依旧先说采用配置文件指定EndPoint(终结点)来调用服务的方式.

依旧是先为Clients项目添加一个app.config配置文件,用WCF服务配置编辑器打开此配置文件,选择客户端添加新的客户端,然后一步步操作下来,得到如下配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <client>
            <endpoint address="http://localhost:9999/CaculatorService" binding="wsHttpBinding"
                contract="WCFService.Contracts.ICaculatorService"
                name="CaculatorService">
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

如前面所描述的,当客户端发起服务请求后,服务端是通过监听与之相匹配的EndPoint来响应请求的,所以上面的配置文件即是为客户端配置一个与服务端配置的终结点相匹配的终结点. 并且为此终结点命名name="Caculator", 程序中采用ChannelFactory创建一个服务代理.

using System;
using System.ServiceModel;
using WCFService.Contracts;

namespace WCFService.Clients
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ChannelFactory<ICaculatorService> channel = new ChannelFactory<ICaculatorService>("CaculatorService"))
            {
                ICaculatorService proxy = channel.CreateChannel();
                using (proxy as IDisposable)
                {
                    Console.WriteLine(proxy.Add(3, 2));
                    Console.WriteLine(proxy.Minus(3, 2));
                    Console.WriteLine(proxy.Multiply(3, 2));
                    Console.WriteLine(proxy.Divide(3, 2));
                }
                Console.ReadKey();
            }
        }
    }
}

OK,运行起来看看结果:

值得注意的是,宿主程序必须是先运行起来的,不然就不能提供服务了.

 

先总结这些,下一篇继续总结如何实现用IIS的工作进程来实现寄宿.

未完待续....

posted @ 2011-09-14 21:35  .Sure  阅读(409)  评论(0编辑  收藏  举报