本系列索引,请见《开篇》
该系列前几篇介绍了 WCF 运行时中的不同扩展点,并且在《Behaviors》文中指出可以通过三种方式来应用这些这些扩展点:Attribute、配置文件及编程方式。这里指的编程方式,就是指在 ServiceHost 中编写代码来应用我们自定义的扩展。
ServiceHost 简介
顾名思义,ServiceHost 就是宿主的意思,一个 SerivceHost 与一个具体的 Service 相关联(,如果要启动多个不同的 Service,需要使用多个 ServiceHost)。WCF 无法自动启动,必须要依赖宿主。这些宿主可以是类似控制台、Winform 的自宿主,也可以是 IIS/WAS 这类的宿主。而这里的宿主最终都是通过实例化ServiceHost,并调用 ServiceHost.Open 方法来启动宿主。
在《消息处理流程》中,我提到过 ServiceHost 在启动阶段所做的事情:初始化所有服务描述(Description)、初始化 ServiceHost 运行时环境、启动监听。
下面的例子描述了一段使用了 ServiceHost 的代码摘自 MSDN:
// Host the service within this EXE console application. public static void Main() { using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService))) { try { // Open the ServiceHost to start listening for messages. serviceHost.Open(); // The service can now be accessed. Console.WriteLine("The service is ready."); Console.WriteLine("Press <ENTER> to terminate service."); Console.ReadLine(); // Close the ServiceHost. serviceHost.Close(); } catch (TimeoutException timeProblem) { Console.WriteLine(timeProblem.Message); Console.ReadLine(); } catch (CommunicationException commProblem) { Console.WriteLine(commProblem.Message); Console.ReadLine(); } } }
ServiceHostFactory 简介
对于自宿主这类应用程序,那 ServiceHost 就够用了。但是如果需要部署在 IIS/WAS 上的话,由于这些宿主环境自已负责构建 ServiceHost 实例,我们无法控制。面对这种情况,WCF 提供了 ServiceHostFactory,让 IIS/WAS 通过它来创建 ServiceHost 实例。
而我们则可以通过继承 ServiceHostFactory 来添加自定义的逻辑。
什么时候需要扩展 ServiceHost ?
有些时候,我们不想使用默认的配置文件(web.config,app.config) 也不想让 Attribute 来污染代码,且还希望逻辑能被重用。
using (ServiceHost host = new ServiceHost(typeof(Service1))) { //Add Descriptions host.Description.Behaviors.Add(new MyBehavior()); //Add endpoint host.AddServiceEndpoint(typeof(IService1), new WSHttpBinding(), ""); host.Open(); //... }
使用上面的代码,当把寄宿环境换成 Winform、WPF,就需要重复写上述逻辑,不利于维护。此时,就应该考虑使用自定义的 ServiceHost 来包装这些逻辑。
扩展 ServiceHost
与之前的扩展不太一样的是,ServiceHost 及 ServiceHostFactory 都是具体的类而非接口,我们只需要继承它们,然后 override 某些方法就可以了。我们可以把逻辑移动到 OnOpening 这个方法。
public class MyServiceHost:ServiceHost { protected override void OnOpening() { //Add Descriptions this.Description.Behaviors.Add(new MyBehavior()); //Add endpoint this.AddServiceEndpoint(typeof(IService1), new WSHttpBinding(), ""); base.OnOpening(); } }
之所以要放在 OnOpening 中是为了确保这些初始化的动作在 Open 之前完成。因为在 Open 之后,这部分设置就变成只读的了,无法进行修改(,即便修改,也不会有任何变化)。
扩展 ServiceHostFactory
前面说了,当需要部署在 IIS/WAS 中,需要借助 ServiceHostFactory。
由于 ServiceHostFactory 存在于 System.ServiceModel.Activation 名称空间中,所以要先引入程序集 "System.ServiceModel.Activation.dll"。
之后,我们就可以通过复写 ServiceHostFactory 中的 CreateServiceHost 来进行扩展了,如:
public class MyServiceHostFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) { return new MyServiceHost(); } }
想要 IIS/WAS 能够使用它,还必须要添加一个 svc 文件,该文件中的标记如下:
<% @ServiceHost Factory="MyServiceHostFactory" Service="Service1" %>
考虑到重用的场景,一般建议尽可能把逻辑放在自定义的 ServiceHost 中,保持 ServiceHostFactory 越简单越好。
参考链接
《WCF Extensibility – ServiceHostFactory》