Wcf 基础教程 服务寄宿之编码实现 ServiceHost

wcf 的服务寄宿方式大致可以分为两种,一种就是自我寄宿,另一种就是通过操作系统的组件进行寄宿。

wcf的服务需要承载于一个被称为宿主的应用程序中。宿主程序为请求监听、消息处理、服务激活、以及操作执行提供了一个运行环境。我们将利用宿主程序来承载服务的操作称为服务寄宿。

 自定义一个控制台应用程序、Windows程序或其他类型的程序作为承载服务的宿主,我们将这种方式称为服务寄宿(Self-Hosting).

另一种就是通过操作系统现有的进程激活方式为wcf服务提供宿主,包括IIS、WAS(Windows激活服务)、Windows 服务等几种。

既然说到了寄宿,我就多说一句,就是IIS寄宿不需要启动,因为IIS会监听,如果有请求会自动启动,当然这些利用Windows下的寄宿方式都不需要启动,但是自我寄宿就需要我们把程序手动的启动。还有就是如果利用IIS寄宿的话,那么只能是采用文件方式,也就是创建*.svc文件的方式。这个我们以后慢慢聊。

今天的主题是通过ServiceHost来进行自我寄宿,ServiceHost就是表示服务宿主。我们采用两种方式,一种就是在有配置文件的情况下的使用,另一种就是在没有配置文件下的使用。

如果你有下载我原来的代码,那么我们把控制台作为宿主的程序中的app.config配置文件删除或者重命名,我重命名为了app11.config.

首先我们了解到ServiceHost继承自ServiceHostBase,而ServiceHostBase又实现了IDisposable接口,也就是说我们可以在使用完以后销毁这个对象。

当然销毁ServiceHost对象的方式有好几种,我们采用using。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.ServiceModel;
 6 using Chinaer.WcfDemo.Contracts;
 7 using System.ServiceModel.Description;
 8 using Chinaer.WcfDemo.Services;
 9 namespace Chinaer.WcfDemo.ConsoleHosting
10 {
11     class Program
12     {
13         static void Main(string[] args)
14         {
15             using (ServiceHost host = new ServiceHost(typeof(CalService), new Uri("http://127.0.0.1:8888/calService")))
16             {
17                 //1.创建ServiceHost对象 这里我们添加了服务的地址,如果这里没有添加服务地址,那么我们在添加服务终结点的时候就需要添加完整路径
18                 //2/添加服务终结点 注意后面的地址我设置为空 因为我在前面添加了地址
19                 host.AddServiceEndpoint(typeof(ICal), new WSHttpBinding(), "");
20                 if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
21                 {
22                     //3.添加元数据终结点 上面添加了这个判断的原因 就是查找配置文件中是否配置了元数据行为 因为我们重命名了配置文件 所以元数据行为肯定为null
23                     ServiceMetadataBehavior metaDataBehavior = new ServiceMetadataBehavior();//创建元数据行为对象
24                     metaDataBehavior.HttpGetEnabled = true;//重点 启用元数据行为的访问
25                     metaDataBehavior.HttpGetUrl = new Uri("http://127.0.0.1:9999/calservice/msdl");
26                     host.Description.Behaviors.Add(metaDataBehavior);//添加元数据行为
27                 }
28                 //添加打开服务宿主的执行函数 本例为匿名函数
29                 host.Opened += delegate {
30                     Console.WriteLine("服务已启动 按任意键退出");
31                 };
32                 try
33                 {
34                     if (host.State != CommunicationState.Opened)
35                     {
36                         host.Open();
37                     }
38 
39                 }
40                 catch (Exception ex)
41                 {
42                     throw ex;
43                 }
44                 Console.Read();
45             }
46 
47         }
48     }
49 }

曾经有一位网友问我,就是服务地址和服务元数据地址是否必须在同一端口下,请注意,我在本例中的服务地址为http://127.0.0.1:8888/calService

而服务元数据地址为http://127.0.0.1:9999/calservice/msdl。是不同的网址

上面演示了在没有配置文件存在的情况下,我们如何启动宿主程序。但是我们如果要在客户端调用这个服务,我们应该引用哪个地址呢?是元数据地址还是服务地址呢?其实如果是单纯的通过添加服务引用的方式,两个地址都可以使用。但是我还是建议,通过添加元数据的方式,毕竟服务是通过元数据发布的。

下面我们添加配置文件,来删减一下ServiceHost编程实现的服务寄宿。记得将我们的配置文件名称更改过来。

 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3   <system.serviceModel>
 4     <services>
 5       <service  name="Chinaer.WcfDemo.Services.CalService" behaviorConfiguration="metaDataBehavior">
 6         <!--<endpoint address=""  binding="wsHttpBinding"></endpoint>-->
 7       </service>
 8     </services>
 9     <behaviors>
10       <serviceBehaviors>
11         <behavior name="metaDataBehavior">
12           <serviceMetadata httpGetEnabled="true"   httpGetUrl="http://127.0.0.1:8888/calservice/metadata"/>
13         </behavior>
14       </serviceBehaviors>
15     </behaviors>
16     <bindings>
17     </bindings>
18   </system.serviceModel>
19 </configuration>

其实上面的配置文件无非就是添加服务元数据行为。其实代码维持我们刚才的也可以,因为存在元数据行为,所以不会为null。但是为了简洁,我们把添加元数据行为的代码删掉。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.ServiceModel;
 6 using Chinaer.WcfDemo.Contracts;
 7 using System.ServiceModel.Description;
 8 using Chinaer.WcfDemo.Services;
 9 namespace Chinaer.WcfDemo.ConsoleHosting
10 {
11     class Program
12     {
13         static void Main(string[] args)
14         {
15             using (ServiceHost host = new ServiceHost(typeof(CalService),new Uri("http://127.0.0.1:8888/calservice")))
16             {
17                 //1.创建ServiceHost对象 这里我们添加了服务的地址,如果这里没有添加服务地址,那么我们在添加服务终结点的时候就需要添加完整路径
18                 //2/添加服务终结点 注意后面的地址我设置为空 因为我在前面添加了地址
19                 //host.AddServiceEndpoint(typeof(ICal), new WSHttpBinding(), "");
20                 //if (host.Description.Behaviors.Find<ServiceMetadataBehavior>() == null)
21                 //{
22                 //    //3.添加元数据终结点 上面添加了这个判断的原因 就是查找配置文件中是否配置了元数据行为 因为我们重命名了配置文件 所以元数据行为肯定为null
23                 //    ServiceMetadataBehavior metaDataBehavior = new ServiceMetadataBehavior();//创建元数据行为对象
24                 //    metaDataBehavior.HttpGetEnabled = true;//重点 启用元数据行为的访问
25                 //    metaDataBehavior.HttpGetUrl = new Uri("http://127.0.0.1:9999/calservice/msdl");
26                 //    host.Description.Behaviors.Add(metaDataBehavior);//添加元数据行为
27                 //}
28                 //添加打开服务宿主的执行函数 本例为匿名函数
29                 host.Opened += delegate {
30                     Console.WriteLine("服务已启动 按任意键退出");
31                 };
32                 try
33                 {
34                     if (host.State != CommunicationState.Opened)
35                     {
36                         host.Open();
37                     }
38 
39                 }
40                 catch (Exception ex)
41                 {
42                     throw ex;
43                 }
44                 Console.Read();
45             }
46 
47         }
48     }
49 }

除了使用using之外,我们销毁ServiceHost的方式

                host.Close();
                host.Abort(); //一般在我们处理捕获到的异常信息时会使用Abort方法销毁异常,而不是close。

ServiceHost就是.Net类库中服务宿主的代名词,我们可以通过它来启动宿主程序。对于宿主我们都是通过配置方式来管理,很少遇到编码的方式,除非以后不需要更改。
其实ServiceHost包括的内容非常多,我们可以获取到服务中所有行为、所有绑定等。需要我们自己慢慢挖掘。

一个人,如果你不逼自己一把,你根本不知道自己有多优秀。

posted @ 2013-03-16 23:36  baidixing  阅读(2671)  评论(2编辑  收藏  举报