Udostępnij za pośrednictwem


Instrukcje: Hostowanie usługi WCF w usłudze zarządzanej systemu Windows

W tym temacie opisano podstawowe kroki wymagane do utworzenia usługi Windows Communication Foundation (WCF), która jest hostowana przez usługę systemu Windows. Scenariusz jest włączony przez zarządzaną opcję hostingu usługi systemu Windows, która jest długotrwałą usługą WCF hostowaną poza usługami Internet Information Services (IIS) w bezpiecznym środowisku, które nie jest aktywowane. Okres istnienia usługi jest kontrolowany przez system operacyjny. Ta opcja hostingu jest dostępna we wszystkich wersjach systemu Windows.

Usługi systemu Windows można zarządzać za pomocą programu Microsoft.ManagementConsole.SnapIn w programie Microsoft Management Console (MMC) i można je skonfigurować do automatycznego uruchamiania po uruchomieniu systemu. Ta opcja hostingu składa się z rejestrowania domeny aplikacji (AppDomain), która hostuje usługę WCF jako zarządzaną usługę systemu Windows, aby okres istnienia procesu usługi był kontrolowany przez menedżera kontroli usług (SCM) dla usług systemu Windows.

Kod usługi zawiera implementację usługi kontraktu usługi, klasę usługi systemu Windows i klasę instalatora. Klasa implementacji usługi, CalculatorService, jest usługą WCF. Jest CalculatorWindowsService to usługa systemu Windows. Aby zakwalifikować się jako usługa systemu Windows, klasa dziedziczy i ServiceBase implementuje OnStart metody i OnStop . W OnStartpliku jest ServiceHost tworzony dla CalculatorService typu i otwarty. W OnStopsystemie usługa jest zatrzymywana i usuwana. Host jest również odpowiedzialny za podanie podstawowego adresu hosta usługi, który został skonfigurowany w ustawieniach aplikacji. Klasa instalatora, która dziedziczy z Installerprogramu , umożliwia zainstalowanie programu jako usługi systemu Windows przez narzędzie Installutil.exe.

Konstruowanie usługi i dostarczanie kodu hostingu

  1. Utwórz nowy projekt aplikacji konsoli programu Visual Studio o nazwie Usługa.

  2. Zmień nazwę Program.cs na Service.cs.

  3. Zmień przestrzeń nazw na Microsoft.ServiceModel.Samples.

  4. Dodaj odwołania do następujących zestawów:

    • System.ServiceModel.dll
    • System.ServiceProcess.dll
    • System.Configuration.Install.dll
  5. Dodaj następujące using dyrektywy, aby 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. Zdefiniuj ICalculator kontrakt usługi, jak pokazano w poniższym kodzie.

    // 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. Zaimplementuj kontrakt usługi w klasie o nazwie CalculatorService , jak pokazano w poniższym kodzie.

    // 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. Utwórz nową klasę o nazwie CalculatorWindowsService , która dziedziczy z ServiceBase klasy . Dodaj zmienną lokalną o nazwie serviceHost , aby odwołać ServiceHost się do wystąpienia. Definiowanie metody wywołującej MainServiceBase.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. Zastąpij metodę OnStart(String[]) , tworząc i otwierając nowe ServiceHost wystąpienie, jak pokazano w poniższym kodzie.

    // 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. Zastąpi metodę zamykającą ServiceHost metodęOnStop, jak pokazano w poniższym kodzie.

    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. Utwórz nową klasę o nazwie ProjectInstaller , która dziedziczy z Installer elementu i jest oznaczona zestawem RunInstallerAttribute na truewartość . Umożliwia to zainstalowanie usługi systemu Windows przez narzędzie Installutil.exe.

    // 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. Usuń klasę Service wygenerowaną podczas tworzenia projektu.

  13. Dodaj plik konfiguracji aplikacji do projektu. Zastąp zawartość pliku następującym kodem XML konfiguracji.

    <?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>
    

    Kliknij prawym przyciskiem myszy plik App.config w Eksplorator rozwiązań i wybierz pozycję Właściwości. W obszarze Kopiuj do katalogu wyjściowego wybierz pozycję Kopiuj, jeśli nowsze.

    W tym przykładzie jawnie określono punkty końcowe w pliku konfiguracji. Jeśli nie dodasz żadnych punktów końcowych do usługi, środowisko uruchomieniowe doda domyślne punkty końcowe. W tym przykładzie, ponieważ usługa ma ustawioną ServiceMetadataBehavior wartość true, usługa ma również włączone metadane publikowania. Aby uzyskać więcej informacji na temat domyślnych punktów końcowych, powiązań i zachowań, zobacz Uproszczone konfigurowanie i uproszczona konfiguracja usług WCF.

Instalowanie i uruchamianie usługi

  1. Skompiluj Service.exe rozwiązanie, aby utworzyć plik wykonywalny.

  2. Otwórz wiersz polecenia dewelopera dla programu Visual Studio i przejdź do katalogu projektu. Wpisz installutil bin\service.exe polecenie w wierszu polecenia, aby zainstalować usługę systemu Windows.

    Wpisz services.msc polecenie w wierszu polecenia, aby uzyskać dostęp do programu Service Control Manager (SCM). Usługa systemu Windows powinna być wyświetlana w obszarze Usługi jako "WCFWindowsServiceSample". Usługa WCF może odpowiadać na klientów tylko wtedy, gdy usługa systemu Windows jest uruchomiona. Aby uruchomić usługę, kliknij ją prawym przyciskiem myszy w SCM i wybierz pozycję "Start" lub wpisz net start WCFWindowsServiceSample w wierszu polecenia.

  3. Jeśli wprowadzisz zmiany w usłudze, musisz go najpierw zatrzymać i odinstalować. Aby zatrzymać usługę, kliknij prawym przyciskiem myszy usługę w SCM i wybierz pozycję "Zatrzymaj" lub wpisz polecenie net stop WCFWindowsServiceSample w wierszu polecenia. Należy pamiętać, że jeśli zatrzymasz usługę systemu Windows, a następnie uruchomisz klienta, EndpointNotFoundException wystąpi wyjątek podczas próby uzyskania dostępu do usługi przez klienta. Aby odinstalować typ usługi systemu Windows installutil /u bin\service.exe w wierszu polecenia.

Przykład

Poniżej znajduje się kompletna lista kodu używanego przez ten temat:

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

Podobnie jak opcja "Self-Hosting", środowisko hostingu usług systemu Windows wymaga, aby część kodu hostingu została napisana w ramach aplikacji. Usługa jest implementowana jako aplikacja konsolowa i zawiera własny kod hostingu. W innych środowiskach hostingu, takich jak usługa aktywacji procesów systemu Windows (WAS) hostowanie w usługach Internet Information Services (IIS), nie jest konieczne, aby deweloperzy pisali kod hostingu.

Zobacz też