【问题标题】:How can I perform initialisation in a WCF service library that isn't self-hosted?如何在非自托管的 WCF 服务库中执行初始化?
【发布时间】:2011-04-21 20:54:23
【问题描述】:

我创建了一个 WCF 服务库,其中包含一个简单的“hello world”测试服务和一个正确配置的 App.config 文件,因此当我启动我的客户端应用程序时,WCF 服务会通过 Visual Studio 的内置主机启动。该服务在我的客户端的外部配置中运行良好。

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

有什么方法可以挂钩库中的一些代码,以便在启动时调用?

【问题讨论】:

  • 你能澄清一下“有什么方法可以挂钩库中的一些代码以在启动时调用吗?”,因为这听起来与“我想使用内置主机以便我不必在开发过程中手动重启服务。”

标签: c# .net wcf visual-studio-2008


【解决方案1】:

我发现另一个关于使用custom ServiceHostFactory to perform bootstrapping 的问题,它是通过*.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 文章 (Hosting and Consuming WCF Services) 解释了 how to do this(清单 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() 覆盖顶部的初始化在照常创建服务之前执行。这似乎每个服务只发生一次,而不是每次调用服务一次,但是多个服务会有开销。通过使用静态标志或类似的东西,这可能是一次性的。目前它似乎工作正常。

【讨论】:

    【解决方案2】:

    在实现您的服务的类的静态构造函数中包含初始化代码是否可行?

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

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

    【讨论】:

    • 这可行,只是当库部署在另一台主机上时,我无法阻止静态构造函数运行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多