作法:在受控的 Windows 服務中裝載 WCF 服務

本主題概述建立由 Windows 服務裝載之 Windows Communication Foundation (WCF) 服務所需的基本步驟。 此情節是透過受管理的 Windows 服務裝載選項來實現,也就是在非訊息啟動的安全環境中於網際網路資訊服務 (IIS) 外部所裝載的長期執行 WCF 服務。 服務的存留期會改由作業系統來控制。 所有 Windows 版本都提供這個裝載選項。

Windows 服務可以透過 Microsoft Management Console (MMC) 中的 Microsoft.ManagementConsole.SnapIn 嵌入式管理單元進行管理,並設定成系統啟動時自動啟動。 此裝載選項包括註冊應用程式定義域 (AppDomain) 以裝載 WCF 服務作為受管理的 Windows 服務,如此一來便可透過 Windows 服務的服務控制管理員 (SCM) 來控制服務的處理序存留期。

服務程式碼包含服務合約的服務實作、Windows 服務類別以及安裝程式類別。 服務實作類別 CalculatorService 是一項 WCF 服務。 CalculatorWindowsService 是一項 Windows 服務。 為了限定為 Windows 服務,此類別會繼承自 ServiceBase,並且實作 OnStartOnStop 方法。 在 OnStart 中,會為 ServiceHost 型別建立並開啟 CalculatorService。 使用 OnStop 時,則會停止與處置服務。 主機也會負責提供服務主機的基底位址,該位址必須設定在應用程式設定中。 繼承自 Installer 的安裝程式類別,會允許 Installutil.exe 工具將程式當做 Windows 服務進行安裝。

建構服務並提供裝載程式碼

  1. 建立新的 Visual Studio 主控台應用程式專案,並命名為 Service

  2. 將 Program.cs 重新命名為 Service.cs。

  3. 將命名空間變更為 Microsoft.ServiceModel.Samples

  4. 加入下列組件的參考:

    • System.ServiceModel.dll

    • System.ServiceProcess.dll

    • System.Configuration.Install.dll

  5. 使用陳述式將下列內容加入至 Service.cs。

    using System.ComponentModel;
    using System.ServiceModel;
    using System.ServiceProcess;
    using System.Configuration;
    using System.Configuration.Install;
    
    Imports System.ComponentModel
    Imports System.ServiceModel
    Imports System.ServiceProcess
    Imports System.Configuration
    Imports System.Configuration.Install
    
  6. 定義 ICalculator 服務合約,如下列程式碼所示。

    // 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);
    }
    
    ' 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
    
  7. CalculatorService 類別中實作服務合約,如下列程式碼所示。

    // 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;
        }
    }
    
    ' 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
    
  8. 建立繼承自 CalculatorWindowsService 類別的新類別,名為 ServiceBase。 加入名為 serviceHost 的區域變數,以參考 ServiceHost 執行個體。 定義 Main 方法來呼叫 ServiceBase.Run(new CalculatorWindowsService)

    public class CalculatorWindowsService : ServiceBase
    {
        public ServiceHost serviceHost = null;
        public CalculatorWindowsService()
        {
            // Name the Windows Service
            ServiceName = "WCFWindowsServiceSample";
        }
    
        public static void Main()
        {
            ServiceBase.Run(new CalculatorWindowsService());
        }
    
    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
    
  9. 建立並開啟新的 OnStart(String[]) 執行個體,以覆寫 ServiceHost 方法,如下列程式碼所示。

    // 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();
    }
    
    ' 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
    
  10. 覆寫用來關閉 OnStopServiceHost 方法,如下列程式碼所示。

    protected override void OnStop()
    {
        if (serviceHost != null)
        {
            serviceHost.Close();
            serviceHost = null;
        }
    }
    
    Protected Overrides Sub OnStop()
        If serviceHost IsNot Nothing Then
            serviceHost.Close()
            serviceHost = Nothing
        End If
    End Sub
    
  11. 建立繼承自 ProjectInstaller 且其 Installer 標記設為 RunInstallerAttribute 的新類別,名為 true。 這樣 Installutil.exe 工具就能安裝此 Windows 服務。

    // 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);
        }
    }
    
    ' 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
    
  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="http://localhost:8000/ServiceModelSamples/service"/>
              </baseAddresses>
            </host>
            <!-- this endpoint is exposed at the base address provided by host: http://localhost:8000/ServiceModelSamples/service  -->
            <endpoint address=""
                      binding="wsHttpBinding"
                      contract="Microsoft.ServiceModel.Samples.ICalculator" />
            <!-- the mex endpoint is exposed at http://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 的開發人員命令提示字元,並瀏覽至專案目錄。 在命令提示字元中輸入 installutil bin\service.exe 以安裝 Windows 服務

    在命令提示字元中輸入 services.msc 以存取服務控制管理員 (SCM)。 Windows 服務應該會在 [服務] 中顯示為 "WCFWindowsServiceSample"。 只有當 Windows 服務正在執行的情況下,WCF 服務才會回應用戶端。 若要啟動服務,請以滑鼠右鍵按一下 SCM 中的服務並選取 [啟動],或是在命令提示字元中鍵入 net start WCFWindowsServiceSample

  3. 若要變更服務,必須先加以停止並解除安裝。 若要停止服務,請以滑鼠右鍵按一下 SCM 中的服務並選取 [停止],或是在命令提示字元中鍵入 net stop WCFWindowsServiceSample。 請注意,如果您在停止 Windows 服務後執行用戶端,則當用戶端嘗試存取此服務時將會發生 EndpointNotFoundException 例外狀況。 若要解除安裝 Windows 服務,請在命令提示字元中鍵入 installutil /u bin\service.exe

範例

以下是這個主題使用過的程式碼完整清單:

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);
        }
    }
}
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

就像「自我裝載」選項一樣,Windows 服務裝載環境要求將某些裝載程式碼撰寫成應用程式的一部分。 服務會實作成為主控台應用程式並包含專屬的裝載程式碼。 在其他裝載環境中,例如 Internet Information Services (IIS) 所裝載的 Windows 處理序啟用服務 (WAS),開發人員就不需要撰寫裝載程式碼。

另請參閱