Como: hospedar um serviço WCF em um serviço Windows gerenciado
Este tópico descreve as etapas básicas necessárias para criar um serviço WCF (Windows Communication Foundation) que é hospedado por um serviço Widnows. O cenário é habilitado pela opção de hospedagem do serviço Windows gerenciado, que é um serviço WCF de execução longa, hospedado fora do IIS (Serviços de Informações da Internet), em um ambiente seguro que não é ativado por mensagem. O tempo de vida do serviço é controlado pelo sistema operacional. Essa opção de hospedagem está disponível em todas as versões do Windows.
Os serviços Windows podem ser gerenciados com o Microsoft.ManagementConsole.SnapIn no MMC (Console de Gerenciamento Microsoft) e podem ser configurados para início automático quando o sistema for inicializado. Essa opção de hospedagem consiste em registrar o domínio do aplicativo (AppDomain) que hospeda um serviço WCF como um serviço Windows gerenciado para que o tempo de vida de processo do serviço seja controlado pelo SCM (Gerenciador de Controle de Serviço) de serviços Windows.
O código do serviço inclui uma implementação de serviço do contrato do serviço, de uma classe do serviço Windows e de uma classe de instalador. A classe de implementação de serviço, CalculatorService
, é um serviço WCF. O CalculatorWindowsService
é um serviço Windows. Para qualificar-se como um serviço Windows, a classe herda de ServiceBase
e implementa os métodos OnStart
e OnStop
. Em OnStart
, um ServiceHost é criado para o tipo CalculatorService
e é aberto. Em OnStop
, o serviço é interrompido e descartado. O host também é responsável por fornecer um endereço básico ao host de serviço, que foi configurado nas configurações do aplicativo. A classe de instalador, que herda de Installer, permite que o programa seja instalado como um serviço Windows pela ferramenta Installutil.exe.
Construir o serviço e fornecer o código de hospedagem
Crie um novo projeto de Aplicativo de Console do Visual Studio chamado Serviço.
Renomeie Program.cs como Service.cs.
Altere o namespace para
Microsoft.ServiceModel.Samples
.Adicione referências aos assemblies a seguir:
- System.ServiceModel.dll
- System.ServiceProcess.dll
- System.Configuration.Install.dll
Adicione as seguintes diretivas
using
ao 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
Defina o contrato de serviço
ICalculator
como mostrado no código a seguir.// 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
Implemente o contrato de serviço em uma classe chamada
CalculatorService
como mostrado no código a seguir.// 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
Crie uma nova classe chamada
CalculatorWindowsService
que herda da classe ServiceBase. Adicione uma variável local chamadaserviceHost
para fazer referência à instância ServiceHost. Defina o métodoMain
que chamaServiceBase.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
Substitua o método OnStart(String[]) criando e abrindo uma nova instância ServiceHost como mostrado no código a seguir.
// 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
Substitua o método OnStop fechando ServiceHost como mostrado no código a seguir.
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
Crie uma nova classe chamada
ProjectInstaller
que herda de Installer e que é marcada com RunInstallerAttribute definido comotrue
. Isso permite que o serviço Windows seja instalado pela ferramenta 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
Remova a classe
Service
que foi gerada quando você criou o projeto.Adicione um arquivo de configuração de aplicativo ao projeto. Substitua o conteúdo do arquivo pelo XML de configuração a seguir.
<?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>
Clique com o botão direito do mouse no arquivo App.config no Gerenciador de Soluções e selecione Propriedades. Em Copiar para Diretório de Saída, selecione Copiar se Mais Recente.
Este exemplo especifica explicitamente pontos de extremidade no arquivo de configuração. Se você não adicionar nenhum ponto de extremidade ao serviço, o runtime adicionará pontos de extremidade padrão para você. Neste exemplo, como o serviço tem ServiceMetadataBehavior definido como
true
, seu serviço também possui metadados de publicação habilitados. Para obter mais informações sobre pontos de extremidade, associações e comportamentos padrão, confira Configuração simplificada e Configuração simplificada para serviços WCF.
Instalar e executar o serviço
Crie a solução para criar o executável
Service.exe
.Abra o Prompt de Comando do Desenvolvedor para Visual Studio e navegue até o diretório do projeto. Digite
installutil bin\service.exe
no prompt de comando para instalar o serviço Windows.Digite
services.msc
no prompt de comando para acessar o SCM. O serviço Windows deve aparecer em Serviços como “WCFWindowsServiceSample”. O serviço WCF só poderá responder aos clientes se o serviço Windows estiver em execução. Para iniciar o serviço, clique com o botão direito do mouse em SCM e selecione “Iniciar”, ou digite net start WCFWindowsServiceSample no prompt de comando.Se você fizer alterações no serviço, interrompa-o primeiro e desinstale-o. Para interromper o serviço, no SCM, clique com o botão direito do mouse no serviço e selecione “Interromper”, ou digite net start WCFWindowsServiceSample no prompt de comando. Observe que se você interromper o serviço Windows e executar um cliente, uma exceção EndpointNotFoundException ocorrerá quando o cliente tentar acessar o serviço. Para desinstalar o serviço Windows, digite installutil /u bin\service.exe no prompt de comando.
Exemplo
Veja a seguir uma listagem completa do código usado por este tópico:
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
Como a opção de "auto-hospedagem", o ambiente de hospedagem de serviços Windows requer que algum código de hospedagem seja criado como parte do aplicativo. O serviço é implementado como um aplicativo de console e contém seu próprio código de hospedagem. Em outros ambientes de hospedagem, como o WAS (Serviço de Ativação de Processos do Windows), hospedado no IIS, não é necessário que os desenvolvedores criem código de hospedagem.