如何:在托管 Windows 服务中承载 WCF 服务

本主题概述了创建由 Windows 服务承载的 Windows Communication Foundation (WCF) 服务所需的基本步骤。此方案可通过托管 Windows 服务承载选项启用,此选项是在没有消息激活的安全环境中在 Internet 信息服务 (IIS) 外部承载的、长时间运行的 WCF 服务。服务的生存期改由操作系统控制。此宿主选项在 Windows 的所有版本中都是可用的。

可以使用 Microsoft 管理控制台 (MMC) 中的 Microsoft.ManagementConsole.SnapIn 管理 Windows 服务,并且可以将其配置为在系统启动时自动启动。此承载选项包括注册承载 WCF 服务作为托管 Windows 服务的应用程序域,因此服务的进程生存期由 Windows 服务的服务控制管理器 (SCM) 来控制。

服务代码包括服务协定的服务实现、Windows 服务类和安装程序类。服务实现类 CalculatorService 是 WCF 服务。CalculatorWindowsService 是 Windows 服务。要符合 Windows 服务的要求,该类继承自 ServiceBase 并实现 OnStartOnStop 方法。在 OnStart 中,将为 CalculatorService 类型创建 ServiceHost 并打开它。在 OnStop 中,停止并释放服务。主机还负责提供服务主机基址,该基址已在应用程序设置中进行设置。安装程序类继承自 Installer,允许程序通过 Installutil.exe 工具安装为 Windows 服务。

构造服务并提供宿主代码

  1. 创建称为“Service”的新 Visual Studio 控制台应用程序项目。

  2. 将 Program.cs 重命名为 Service.cs。

  3. 将命名空间更改为 Microsoft.ServiceModel.Samples。

  4. 添加对下列程序集的引用。

    • System.ServiceModel.dll

    • System.ServiceProcess.dll

    • System.Configuration.Install.dll

  5. 将下面的 using 语句添加到 Service.cs。

    Imports System.ComponentModel
    Imports System.ServiceModel
    Imports System.ServiceProcess
    Imports System.Configuration
    Imports System.Configuration.Install
    
    using System.ComponentModel;
    using System.ServiceModel;
    using System.ServiceProcess;
    using System.Configuration;
    using System.Configuration.Install;
    
  6. 定义 ICalculator 服务协定,如下面的代码所示。

    ' Define a service contract.
    <ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples")> _
    Public Interface ICalculator
        <OperationContract()> _
        Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double
        <OperationContract()> _
        Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double
        <OperationContract()> _
        Function Multiply(ByVal n1 As Double, ByVal n2 As Double) As Double
        <OperationContract()> _
        Function Divide(ByVal n1 As Double, ByVal n2 As Double) As Double
    End Interface
    
    // Define a service contract.
    [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
    public interface ICalculator
    {
        [OperationContract]
        double Add(double n1, double n2);
        [OperationContract]
        double Subtract(double n1, double n2);
        [OperationContract]
        double Multiply(double n1, double n2);
        [OperationContract]
        double Divide(double n1, double n2);
    }
    
  7. 在称为 CalculatorService 的类中实现服务协定,如下面的代码所示。

    ' Implement the ICalculator service contract in a service class.
    Public Class CalculatorService
        Implements ICalculator
        ' Implement the ICalculator methods.
        Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Add
            Return n1 + n2
    
        End Function
    
        Public Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Subtract
            Return n1 - n2
    
        End Function
    
        Public Function Multiply(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Multiply
            Return n1 * n2
        End Function
    
        Public Function Divide(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Divide
            Return n1 / n2
    
        End Function
    End Class
    
    // Implement the ICalculator service contract in a service class.
    public class CalculatorService : ICalculator
    {
        // Implement the ICalculator methods.
        public double Add(double n1, double n2)
        {
            double result = n1 + n2;
            return result;
        }
    
        public double Subtract(double n1, double n2)
        {
            double result = n1 - n2;
            return result;
        }
    
        public double Multiply(double n1, double n2)
        {
            double result = n1 * n2;
            return result;
        }
    
        public double Divide(double n1, double n2)
        {
            double result = n1 / n2;
            return result;
        }
    }
    
  8. 创建从 ServiceBase 类继承的称为 CalculatorWindowsService 的新类。添加称为 serviceHost 的局部变量以引用 ServiceHost 实例。定义调用 ServiceBase.Run(new CalculatorWindowsService)Main 方法

    Public Class CalculatorWindowsService
        Inherits ServiceBase
        Public serviceHost As ServiceHost = Nothing
        Public Sub New()
            ' Name the Windows Service
            ServiceName = "WCFWindowsServiceSample"
        End Sub
    
        Public Shared Sub Main()
            ServiceBase.Run(New CalculatorWindowsService())
        End Sub
    
    public class CalculatorWindowsService : ServiceBase
    {
        public ServiceHost serviceHost = null;
        public CalculatorWindowsService()
        {
            // Name the Windows Service
            ServiceName = "WCFWindowsServiceSample";
        }
    
        public static void Main()
        {
            ServiceBase.Run(new CalculatorWindowsService());
        }
    
  9. 通过创建并打开新 ServiceHost 实例重写 OnStart 方法,如下面的代码所示。

    ' Start the Windows service.
    Protected Overrides Sub OnStart(ByVal args() As String)
        If serviceHost IsNot Nothing Then
            serviceHost.Close()
        End If
    
        ' Create a ServiceHost for the CalculatorService type and 
        ' provide the base address.
        serviceHost = New ServiceHost(GetType(CalculatorService))
    
        ' Open the ServiceHostBase to create listeners and start 
        ' listening for messages.
        serviceHost.Open()
    End Sub
    
    // Start the Windows service.
    protected override void OnStart(string[] args)
    {
        if (serviceHost != null)
        {
            serviceHost.Close();
        }
    
        // Create a ServiceHost for the CalculatorService type and 
        // provide the base address.
        serviceHost = new ServiceHost(typeof(CalculatorService));
    
        // Open the ServiceHostBase to create listeners and start 
        // listening for messages.
        serviceHost.Open();
    }
    
  10. 通过关闭 ServiceHost 重写 OnStop 方法,如下面的代码所示。

    Protected Overrides Sub OnStop()
        If serviceHost IsNot Nothing Then
            serviceHost.Close()
            serviceHost = Nothing
        End If
    End Sub
    
    protected override void OnStop()
    {
        if (serviceHost != null)
        {
            serviceHost.Close();
            serviceHost = null;
        }
    }
    
  11. 创建称为 ProjectInstaller 的新类,该类继承自 Installer,且其 RunInstallerAttribute 设置为 true。这允许 Windows 服务由 Installutil.exe 工具安装。

       ' Provide the ProjectInstaller class which allows 
       ' the service to be installed by the Installutil.exe tool
       <RunInstaller(True)> _
    Public Class ProjectInstaller
           Inherits Installer
           Private process As ServiceProcessInstaller
           Private service As ServiceInstaller
    
           Public Sub New()
               process = New ServiceProcessInstaller()
               process.Account = ServiceAccount.LocalSystem
               service = New ServiceInstaller()
               service.ServiceName = "WCFWindowsServiceSample"
               Installers.Add(process)
               Installers.Add(service)
           End Sub
       End Class
    
    // Provide the ProjectInstaller class which allows 
    // the service to be installed by the Installutil.exe tool
    [RunInstaller(true)]
    public class ProjectInstaller : Installer
    {
        private ServiceProcessInstaller process;
        private ServiceInstaller service;
    
        public ProjectInstaller()
        {
            process = new ServiceProcessInstaller();
            process.Account = ServiceAccount.LocalSystem;
            service = new ServiceInstaller();
            service.ServiceName = "WCFWindowsServiceSample";
            Installers.Add(process);
            Installers.Add(service);
        }
    }
    
  12. 移除当您创建项目时生成的 Service 类。

  13. 将应用程序配置文件添加到项目中。将文件内容替换为下面的配置 XML。

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>    <services>
          <!-- This section is optional with the new configuration model
               introduced in .NET Framework 4. -->
          <service name="Microsoft.ServiceModel.Samples.CalculatorService"
                   behaviorConfiguration="CalculatorServiceBehavior">
            <host>
              <baseAddresses>
                <add baseAddress="https://localhost:8000/ServiceModelSamples/service"/>
              </baseAddresses>
            </host>
            <!-- this endpoint is exposed at the base address provided by host: https://localhost:8000/ServiceModelSamples/service  -->
            <endpoint address=""
                      binding="wsHttpBinding"
                      contract="Microsoft.ServiceModel.Samples.ICalculator" />
            <!-- the mex endpoint is exposed at https://localhost:8000/ServiceModelSamples/service/mex -->
            <endpoint address="mex"
                      binding="mexHttpBinding"
                      contract="IMetadataExchange" />
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="CalculatorServiceBehavior">
              <serviceMetadata httpGetEnabled="true"/>
              <serviceDebug includeExceptionDetailInFaults="False"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>
    

    在**“解决方案资源管理器”中右击 App.config 文件,然后选择“属性”。在“复制到输出目录”下,选择“如果较新则复制”**。

    此示例显式指定配置文件中的终结点。如果您不希望向服务添加任何终结点,则运行时为您添加默认终结点。在此示例中,由于服务的 ServiceMetadataBehavior 设置为 true,因此服务还启用了发布元数据。有关默认终结点、绑定和行为的更多信息,请参见简化配置WCF 服务的简化配置

安装并运行服务

  1. 生成解决方案以创建 Service.exe 可执行文件。

  2. 打开 Visual Studio 2010 命令提示,导航到项目目录。在命令提示符处键入 installutil bin\service.exe 来安装 Windows 服务。

    ms733069.note(zh-cn,VS.100).gif注意:
    如果您不使用 Visual Studio 2010 命令提示,请确保 %WinDir%\Microsoft.NET\Framework\v4.0.<current version> 目录位于系统路径中。

    在命令提示符处键入 services.msc 以访问服务控制管理器 (SCM)。Windows 服务应作为“WCFWindowsServiceSample”出现在服务中。只有在 Windows 服务正在运行的情况下,WCF 服务才能响应客户端。若要启动该服务,请在 SCM 中右击它,然后选择“启动”,或者在命令提示符下键入 net start WCFWindowsServiceSample

  3. 如果对服务进行更改,则必须首先停止并卸载服务。若要停止该服务,请在 SCM 中右击该服务,然后选择“停止”,或者在命令提示符下键入 net stop WCFWindowsServiceSample。请注意,如果停止 Windows 服务然后运行客户端,则在客户端尝试访问该服务时,会发生 EndpointNotFoundException 异常。若要卸载 Windows 服务,请在命令提示符下键入 installutil /u bin\service.exe

示例

下面是本主题使用的代码的完整列表。

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text

Imports System.ComponentModel
Imports System.ServiceModel
Imports System.ServiceProcess
Imports System.Configuration
Imports System.Configuration.Install

Namespace Microsoft.ServiceModel.Samples
    ' Define a service contract.
    <ServiceContract(Namespace:="http://Microsoft.ServiceModel.Samples")> _
    Public Interface ICalculator
        <OperationContract()> _
        Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double
        <OperationContract()> _
        Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double
        <OperationContract()> _
        Function Multiply(ByVal n1 As Double, ByVal n2 As Double) As Double
        <OperationContract()> _
        Function Divide(ByVal n1 As Double, ByVal n2 As Double) As Double
    End Interface

    ' Implement the ICalculator service contract in a service class.
    Public Class CalculatorService
        Implements ICalculator
        ' Implement the ICalculator methods.
        Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Add
            Return n1 + n2

        End Function

        Public Function Subtract(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Subtract
            Return n1 - n2

        End Function

        Public Function Multiply(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Multiply
            Return n1 * n2
        End Function

        Public Function Divide(ByVal n1 As Double, ByVal n2 As Double) As Double Implements ICalculator.Divide
            Return n1 / n2

        End Function
    End Class

    Public Class CalculatorWindowsService
        Inherits ServiceBase
        Public serviceHost As ServiceHost = Nothing
        Public Sub New()
            ' Name the Windows Service
            ServiceName = "WCFWindowsServiceSample"
        End Sub

        Public Shared Sub Main()
            ServiceBase.Run(New CalculatorWindowsService())
        End Sub

        ' Start the Windows service.
        Protected Overrides Sub OnStart(ByVal args() As String)
            If serviceHost IsNot Nothing Then
                serviceHost.Close()
            End If

            ' Create a ServiceHost for the CalculatorService type and 
            ' provide the base address.
            serviceHost = New ServiceHost(GetType(CalculatorService))

            ' Open the ServiceHostBase to create listeners and start 
            ' listening for messages.
            serviceHost.Open()
        End Sub

        Protected Overrides Sub OnStop()
            If serviceHost IsNot Nothing Then
                serviceHost.Close()
                serviceHost = Nothing
            End If
        End Sub
    End Class
    ' Provide the ProjectInstaller class which allows 
    ' the service to be installed by the Installutil.exe tool
    <RunInstaller(True)> _
 Public Class ProjectInstaller
        Inherits Installer
        Private process As ServiceProcessInstaller
        Private service As ServiceInstaller

        Public Sub New()
            process = New ServiceProcessInstaller()
            process.Account = ServiceAccount.LocalSystem
            service = New ServiceInstaller()
            service.ServiceName = "WCFWindowsServiceSample"
            Installers.Add(process)
            Installers.Add(service)
        End Sub
    End Class
End Namespace
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ComponentModel;
using System.ServiceModel;
using System.ServiceProcess;
using System.Configuration;
using System.Configuration.Install;

namespace Microsoft.ServiceModel.Samples
{
    // Define a service contract.
    [ServiceContract(Namespace = "http://Microsoft.ServiceModel.Samples")]
    public interface ICalculator
    {
        [OperationContract]
        double Add(double n1, double n2);
        [OperationContract]
        double Subtract(double n1, double n2);
        [OperationContract]
        double Multiply(double n1, double n2);
        [OperationContract]
        double Divide(double n1, double n2);
    }

    // Implement the ICalculator service contract in a service class.
    public class CalculatorService : ICalculator
    {
        // Implement the ICalculator methods.
        public double Add(double n1, double n2)
        {
            double result = n1 + n2;
            return result;
        }

        public double Subtract(double n1, double n2)
        {
            double result = n1 - n2;
            return result;
        }

        public double Multiply(double n1, double n2)
        {
            double result = n1 * n2;
            return result;
        }

        public double Divide(double n1, double n2)
        {
            double result = n1 / n2;
            return result;
        }
    }

    public class CalculatorWindowsService : ServiceBase
    {
        public ServiceHost serviceHost = null;
        public CalculatorWindowsService()
        {
            // Name the Windows Service
            ServiceName = "WCFWindowsServiceSample";
        }

        public static void Main()
        {
            ServiceBase.Run(new CalculatorWindowsService());
        }

        // Start the Windows service.
        protected override void OnStart(string[] args)
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
            }

            // Create a ServiceHost for the CalculatorService type and 
            // provide the base address.
            serviceHost = new ServiceHost(typeof(CalculatorService));

            // Open the ServiceHostBase to create listeners and start 
            // listening for messages.
            serviceHost.Open();
        }

        protected override void OnStop()
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
                serviceHost = null;
            }
        }
    }

    // Provide the ProjectInstaller class which allows 
    // the service to be installed by the Installutil.exe tool
    [RunInstaller(true)]
    public class ProjectInstaller : Installer
    {
        private ServiceProcessInstaller process;
        private ServiceInstaller service;

        public ProjectInstaller()
        {
            process = new ServiceProcessInstaller();
            process.Account = ServiceAccount.LocalSystem;
            service = new ServiceInstaller();
            service.ServiceName = "WCFWindowsServiceSample";
            Installers.Add(process);
            Installers.Add(service);
        }
    }
}

与“自承载”选项一样,Windows 服务宿主环境要求写入一些宿主代码作为应用程序的一部分。该服务作为控制台应用程序实现,且包含其自己的宿主代码。在其他宿主环境(如 Internet 信息服务 (IIS) 中的 Windows 进程激活服务 (WAS) 宿主)中,开发人员没有必要编写宿主代码。

另请参见

概念

简化配置
在托管应用程序中承载
承载服务

其他资源

Windows Server App Fabric 承载功能