上篇博客已经说明了WCF的一个服务如何创建,那么创建好了服务之后,我们如何发布出去呢?要想完整的做完一个WCF服务,一共分三步走,第一步就是像上篇博客所说创建服务,第二步是发布服务,还有最后一步就是客户端调用服务。今天重点说发布服务。说到发布,不得不说一下WCF的宿主。说到宿主,又不得不说一下Endpoint。
首先,宿主是什么?
通俗的说就是,当我们写好了一个服务之后,要有地方放它,才能让客户端调用的时候找到它,这就是宿主,它是一种媒介,是一个位置。WCF在运行时必寄宿在“宿主程序”之上,WCF本身不能够独自运行(每个WCF服务必须宿主在一个Windows进程中)。而我们最熟悉的发布到IIS服务器上,其实IIS也是一种宿主。也就是说,WCF想要向外提供服务,那么就需要一个宿主来容纳这些服务。
然后,介绍一下Endpoint。
当我们寄宿WCF服务的时候,我们必须定义一个或是多个终结点,然后Serivce端通过监听这些终结点来处理Client发来的请求。由于应用程序之间是靠Endpoint来通信的,那么我们在Client端也必须定义终结点,只有当Client与Service的终结点完全匹配的时候才能进行通信。可以说Endpoint是一个双方识别对方的钥匙,只有匹配好了才会进行合作。
A、B、C即是Endpoint 的组成部分,它是服务器间通信调用的入口。
(1)A(Address):A解决了:Whereto locate the WCF Service?
在计算机中是通过一个URI唯一地址标识,通过这个地址我们可以找到我们要调用的WCF服务。
(2)B(Binding):B解决了:Howto communicate with service?
Binding实现在Client和Service通信的所有底层细节。如:我们在客户端与服务端传输的时候采用的是什么样的编码,XML?Text?二进制?采用哪种传输协议进行传输,TCP?Http?以及采用什么样的机制解决安全问题,SSL?加密?……
(3)C(Contract):C解决了:Whatfunctionalities do the Service provide?
Contract的主要的作用是暴露某个WCFService所提供的所有有效的方法。Contract实际上是把每个方法的转化成为相对应的消息。
接下来WCF的三种宿主方式
1、IIS宿主
把WCF寄宿在IIS之上,在IIS中宿主一个服务的主要优点是在发生客户端请求时宿主进程会被自动启动,也就是在我们的服务端没有通过配置文件来写终结点了,IIS都帮我们做了,所以说大多数人还是经常用IIS来发布服务的。并且你可以依靠IIS来管理宿主进程的生命周期,在开发和使用的过程与WebService非常相似。发布IIS就是传统的我们使用的发布方法,发布成功如下图。曾几何时,一见到这个干净的成功页面时就欢呼雀跃。
2、手写代码宿主
当使用IIS或者WAS作为宿主程序时,IIS和WAS会自动创建ServiceHost类型。但是当编写自定义的宿主程序时就需要我们手动的创建这个对象了。
事实上,宿主的选择和绑定有着密切的关系的。比如选择IIS作为宿主,必须采用Http作为通信协议来绑定。我们使用自定义的程序作为宿主,必须根据绑定协议来编写相应的代码。服务的地址需要根据绑定所采用的通信协议来最终确立。所以绑定、协议都在宿主程序中去定义。
宿主程序包含着一个公共的接口,这个接口就暴露出了服务的地址、契约、绑定,也就是终结点。
这是手动创建宿主的基本语法:
Public ServiceHost(Type serviceType,params Uri[] baseAddresses); //两个参数分别是:serviceType服务契约定义的类型,baseAddresses一组长度可变的基地址数组
在宿主中,首先要定义一个服务对象,然后定义好终结点需要的三要素添加终结点,最后开启服务。ServiceHost对象会自动有一个销毁服务的方法,为的是当关闭这个服务的时候就销毁它。
具体的步骤及代码如下:
public class MyHelloHost:IDisposable { private ServiceHost _myhost; //定义一个当前类的对象,服务对象 public ServiceHost Myhost { get { return _myhost; } } //定义一个终结点的基地址:包含一个基本的传输协议 public const string BaseAddress = "net.pipe://localhost"; //定义一个可选地址,可以选择性的定义 public const string HelloServiceAddress = "Hello"; //定义服务契约的实现类型 public static readonly Type ServiceType = typeof(HelloService.HelloService); //服务契约的定义类型:接口 public static readonly Type ContractType = typeof(HelloService.IHelloService); //定义一个服务绑定 public static readonly Binding hellobinding = new NetNamedPipeBinding(); //构造一个服务对象 protected void CreateHelloServiceHost() { //创建服务对象:实例化声明的服务对象 服务类型,基地址 _myhost = new ServiceHost(ServiceType, new Uri[] { new Uri(BaseAddress) }); //添加终结点 服务的契约类型,绑定,可选地址 _myhost.AddServiceEndpoint(ContractType, hellobinding, HelloServiceAddress); } //定义一个打开服务的方法,只有服务打开之后,客户端才能访问服务 public void open() { Console.WriteLine("开始启动服务 ……"); _myhost.Open(); Console.WriteLine("服务已经启动 ……"); } //构造方法:作用调用当前方法创建一个服务对象 public MyHelloHost() { CreateHelloServiceHost(); } //销毁服务宿主对象实例,关闭这个服务的时候就销毁 public void Dispose() { if (_myhost!=null) { (_myhost as IDisposable).Dispose(); } } }
3、写到配置文件里
发布服务的前提是我们已经创建好了一个服务。配置文件里面配置好宿主程序也就是配置终结点,即配置地址、绑定、契约。
<system.serviceModel> <services> <service name="WinformHello.HelloService" behaviorConfiguration="TestBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:8001/Hello"/> </baseAddresses> </host> <endpoint address="" binding="basicHttpBinding" contract="WCFServiceConfig.IHelloService"></endpoint> </service> </services> <behaviors> <serviceBehaviors> <behavior name="TestBehavior"> <!-- 这句话的意思是:为避免泄漏元数据信息,在部署前将以下值设置为 false 并删除上面的元数据终结点--> <serviceMetadata httpGetEnabled="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
其实WCF的宿主还可以是 Windows服务、COM+应用程序、WAS(Windows ActivationServices,Windows进程激活服务)IIS、Windows应用程序,或简单的控制台应用程序及任何.net程序。这里小乖也只是相对而言比较熟悉上面所述的三种,所以先拿出来卖个萌。
这篇文章讲的是在既创建服务之后的发布服务,接下来将是该如何调用一个服务或者多个服务了。未完,待续……