如何在非自托管的WCF服务库中执行初始化?

本文关键字:服务 执行 初始化 WCF | 更新日期: 2023-09-27 17:50:32

我用一个简单的'hello world'测试服务和一个正确配置的App.config文件创建了一个WCF服务库,这样当我启动我的客户端应用程序时,WCF服务就会通过Visual Studio的内置主机启动。该服务目前在我的客户端的外部配置下工作良好。

我需要运行一些初始化代码来设置DI,数据访问,日志记录等。我已经编写了一个控制台主机,可以做到这一点,服务本身最终将作为Windows服务部署,但我想使用内置主机,这样我就不必在开发期间手动重启服务。

是否有一些方法我可以钩一些代码在库中被调用启动?

如何在非自托管的WCF服务库中执行初始化?

我发现了另一个关于使用自定义ServiceHostFactory执行引导的问题,这是通过*.svc文件设置的。*.svc文件是WCF服务应用程序的一部分,不能直接被WCF服务库使用。我想坚持使用服务库,以便在实现服务和最终的生产托管时具有一定的灵活性,但是使用WCF服务应用程序将以适合开发的方式完成工作(并且可能很容易使用IIS进行生产托管,并使用另一组配置)。因此,我认为我只需要创建一个WCF服务应用程序,它充当服务库中服务的主机,并执行所需的初始化。

我首先创建了一个新的WCF服务应用程序,删除了VS创建的默认服务文件,并添加了对现有服务库和其他依赖项的引用。

在服务应用程序的Web.Config文件中,在<configSections>..</configSections>部分(需要是<configuration>标记之后的第一个节点)下,我为服务库添加了<system.serviceModel>部分(这可以从服务库中的App.config文件中提取并编辑以适应)。

例如:

<system.serviceModel>
  <services>
    <service behaviorConfiguration="MyServiceBehavior" name="BelfryImages.QueryService.Implementation.HelloWorld">
      <endpoint address="HelloWorld" binding="wsHttpBinding" name="HelloWorld" contract="BelfryImages.QueryService.Contracts.IHelloWorld" />
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name="MyServiceBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <bindings>
  </bindings>
</system.serviceModel>

注意BelfryImages.QueryService.Implementation.HelloWorld是服务契约(接口)BelfryImages.QueryService.Contracts.IHelloWorld的服务实现(实现类)的FQN。实际上我有两个独立的组件;BelfryImages.QueryService.Contracts.dll是WCF服务库。

我向服务应用程序添加了一个新的空白.svc文件,其命名与端点匹配,例如HelloWorld.svc。通常,将WCF服务添加到WCF服务应用程序中会产生一个.svc文件和一个.cs代码隐藏文件,其中包含服务的实现。我只手动添加了没有隐藏代码的.svc文件,并将其指向服务库实现:

<%@ ServiceHost Language="C#" Debug="true" Service="BelfryImages.QueryService.Implementation.HelloWorld" %>

在将客户端的服务URL从http://localhost:XXXXX/QueryService/HelloWorld更改为http://localhost:XXXXX/HelloWorld.svc/HelloWorld之后,它可以作为vs托管服务库的临时替代品使用。

然后,我创建了ServiceHostFactory来执行服务的初始化。我找到了一篇MSDN文章(托管和消费WCF服务),它解释了如何做到这一点(清单5-6和5-7)——出于我的目的,我只添加了一个更简单的通用CustomHostFactory类:
public class CustomHostFactory
    : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        // perform initialisation:
        ...
        var serviceHost = base.CreateServiceHost(serviceType, baseAddresses);
        return serviceHost;
    }
}

然后通过添加Factory属性将其绑定到.svc文件中的服务:

<%@ ServiceHost Language="C#" Debug="true" Service="BelfryImages.QueryService.Implementation.HelloWorld" Factory="BelfryImages.WcfService.CustomHostFactory" %>

CreateServiceHost()覆盖的顶部执行初始化,然后像往常一样创建服务。这似乎只在每个服务中发生一次,而不是在对服务的每次调用中发生一次,但是多个服务会产生开销。这可以通过使用静态标志或类似的方法一次性完成。

将初始化代码放在实现服务的类的静态构造函数中可以吗?

public class WCFService : IWCFService
{
    static WCFService()
    {
        // do initializing here
    }
}

此代码将在第一次调用服务时执行。