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包括的内容非常多,我们可以获取到服务中所有行为、所有绑定等。需要我们自己慢慢挖掘。
一个人,如果你不逼自己一把,你根本不知道自己有多优秀。
我又回来了,回到了技术最前线,