Compartilhar via


Especificando um endereço de ponto de extremidade

Toda a comunicação com um serviço WCF (Windows Communication Foundation) ocorre por meio de pontos de extremidade. Cada ServiceEndpoint contém um Address, um Binding e um Contract. O contrato especifica quais operações estão disponíveis. A associação especifica como se comunicar com o serviço e o endereço especifica onde localizar o serviço. Cada ponto de extremidade deve ter um endereço exclusivo. O endereço do ponto de extremidade é representado pela classe EndpointAddress, que contém um URI (Uniform Resource Identifier) que representa o endereço do serviço, um Identity, que representa a identidade de segurança do serviço e uma coleção de Headers opcionais. Os cabeçalhos opcionais fornecem informações de endereçamento mais detalhadas para identificar ou interagir com o ponto de extremidade. Por exemplo, cabeçalhos podem indicar como processar uma mensagem de entrada, onde o ponto de extremidade deve enviar uma mensagem de resposta ou qual instância de um serviço usar para processar uma mensagem de entrada de um usuário específico quando várias instâncias estiverem disponíveis.

Definição de um endereço de ponto de extremidade

No WCF, um EndpointAddress modela a referência de um ponto de extremidade (EPR) conforme definido no padrão WS-Addressing.

O URI de endereço para a maioria dos transportes tem quatro partes. Por exemplo, esse URI http://www.fabrikam.com:322/mathservice.svc/secureEndpoint tem as quatro partes a seguir:

  • Esquema: http:

  • Computador: www.fabrikam.com

  • (Opcional) Porta: 322

  • Caminho: /mathservice.svc/secureEndpoint

Parte do modelo de EPR é que cada referência de ponto de extremidade pode carregar alguns parâmetros de referência que adicionam informações de identificação extra. No WCF, esses parâmetros de referência são modelados como instâncias da AddressHeader classe.

O endereço do ponto de extremidade de um serviço pode ser especificado de forma imperativa usando código ou declarativamente por meio da configuração. A definição de pontos de extremidade no código não costuma ser prática, porque as associações e os endereços de um serviço implantado normalmente são diferentes daqueles usados conforme o serviço está sendo desenvolvido. Geralmente, é mais prático definir pontos de extremidade de serviço usando configuração em vez de código. Manter as informações de endereçamento e associação fora do código permite que elas sejam alteradas sem a necessidade de compilar ou implantar novamente o aplicativo. Se nenhum ponto de extremidade for especificado no código ou na configuração, o runtime adicionará um ponto de extremidade padrão em cada endereço base para cada contrato implementado pelo serviço.

Há duas maneiras de especificar endereços de ponto de extremidade para um serviço no WCF. Você pode especificar um endereço absoluto para cada ponto de extremidade associado ao serviço ou fornecer um endereço base para o ServiceHost de um serviço e especificar um endereço para cada ponto de extremidade associado a esse serviço definido em relação a esse endereço base. Você pode usar cada um desses procedimentos para especificar os endereços de ponto de extremidade para um serviço em configuração ou código. Se você não especificar um endereço relativo, o serviço usará o endereço base. Você também pode ter vários endereços base para um serviço, mas cada serviço tem permissão para apenas um endereço base para cada transporte. Caso tenha vários pontos de extremidade, cada um configurado com uma associação diferente, seus endereços deverão ser exclusivos. Pontos de extremidade que usam a mesma associação, mas contratos diferentes podem usar o mesmo endereço.

Ao hospedar com o IIS, você não gerencia a instância ServiceHost por conta própria. O endereço base é sempre o endereço especificado no arquivo .svc para o serviço ao hospedar no IIS. Portanto, você deve usar endereços de ponto de extremidade relativos para pontos de extremidade de serviço hospedados no IIS. Fornecer um endereço de ponto de extremidade totalmente qualificado pode levar a erros na implantação do serviço. Para obter mais informações, consulte Implantando um Serviço WCF hospedado em Serviços de Informações da Internet.

Definindo endereços de ponto de extremidade na configuração

Para definir um ponto de extremidade em um arquivo de configuração, use o elemento <ponto de extremidade>.

<configuration>
  <system.serviceModel>
    <services>
      <service name="UE.Samples.HelloService"
               behaviorConfiguration="HelloServiceBehavior">
        <endpoint address="/Address1"
                  binding="basicHttpBinding" 
                  contract="UE.Samples.IHello"/>

        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="HelloServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Quando o método Open é chamado (ou seja, quando o aplicativo de hospedagem tenta iniciar o serviço), o sistema procura um elemento de <serviço> com um atributo de nome que especifica "UE. Samples.HelloService". Se o elemento de <serviço> for encontrado, o sistema carregará a classe especificada e criará pontos de extremidade usando as definições de ponto de extremidade fornecidas no arquivo de configuração. Esse mecanismo permite que você carregue e inicie um serviço com duas linhas de código mantendo as informações de associação e endereçamento fora do código. A vantagem dessa abordagem é que essas alterações podem ser feitas sem precisar recompilar ou reimplantar o aplicativo.

Os cabeçalhos opcionais são declarados em <cabeçalhos>. Veja a seguir um exemplo dos elementos usados para especificar pontos de extremidade para um serviço em um arquivo de configuração que distingue entre dois cabeçalhos: clientes "Gold" de http://tempuri1.org/ e clientes "Standard" de http://tempuri2.org/. O cliente que chama esse serviço deve ter os <cabeçalhos> apropriados no arquivo de configuração.

<configuration>
  <system.serviceModel>
    <services>
      <service name="UE.Samples.HelloService"
               behaviorConfiguration="HelloServiceBehavior">
        <endpoint address="/Address1"
                  binding="basicHttpBinding" 
                  contract="UE.Samples.IHello">
          <headers>
            <Member xmlns="http://tempuri1.org/">Gold</Member>
          </headers>
        </endpoint>
        <endpoint address="/Address2"
          binding="basicHttpBinding" 
          contract="UE.Samples.IHello">
          <headers>
            <Member xmlns="http://tempuri2.org/">Silver</Member>
          </headers>
        </endpoint>

        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="HelloServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Os cabeçalhos também podem ser definidos em mensagens individuais em vez de todas as mensagens em um ponto de extremidade (conforme mostrado anteriormente). Isso é feito usando OperationContextScope para criar um novo contexto em um aplicativo cliente para adicionar um cabeçalho personalizado à mensagem de saída, conforme mostrado no exemplo a seguir.

SampleServiceClient wcfClient = new SampleServiceClient(new InstanceContext(this));
try
{
  using (OperationContextScope scope = new OperationContextScope(wcfClient.InnerChannel))
  {
    MessageHeader header
      = MessageHeader.CreateHeader(
      "Service-Bound-CustomHeader",
      "http://Microsoft.WCF.Documentation",
      "Custom Happy Value."
      );
    OperationContext.Current.OutgoingMessageHeaders.Add(header);

    // Making calls.
    Console.WriteLine("Enter the greeting to send: ");
    string greeting = Console.ReadLine();

    //Console.ReadLine();
    header = MessageHeader.CreateHeader(
        "Service-Bound-OneWayHeader",
        "http://Microsoft.WCF.Documentation",
        "Different Happy Value."
      );
    OperationContext.Current.OutgoingMessageHeaders.Add(header);

    // One-way
    wcfClient.Push(greeting);
    this.wait.WaitOne();

    // Done with service.
    wcfClient.Close();
    Console.WriteLine("Done!");
    Console.ReadLine();
  }
}
catch (TimeoutException timeProblem)
{
  Console.WriteLine("The service operation timed out. " + timeProblem.Message);
  Console.ReadLine();
  wcfClient.Abort();
}
catch (CommunicationException commProblem)
{
  Console.WriteLine("There was a communication problem. " + commProblem.Message);
  Console.ReadLine();
  wcfClient.Abort();
}
Dim wcfClient As New SampleServiceClient(New InstanceContext(Me))
Try
    Using scope As New OperationContextScope(wcfClient.InnerChannel)
        Dim header As MessageHeader = MessageHeader.CreateHeader("Service-Bound-CustomHeader", _
                            "http://Microsoft.WCF.Documentation", "Custom Happy Value.")
        OperationContext.Current.OutgoingMessageHeaders.Add(header)

        ' Making calls.
        Console.WriteLine("Enter the greeting to send: ")
        Dim greeting As String = Console.ReadLine()

        'Console.ReadLine();
        header = MessageHeader.CreateHeader("Service-Bound-OneWayHeader", _
                                            "http://Microsoft.WCF.Documentation", "Different Happy Value.")
        OperationContext.Current.OutgoingMessageHeaders.Add(header)

        ' One-way
        wcfClient.Push(greeting)
        Me.wait.WaitOne()

        ' Done with service. 
        wcfClient.Close()
        Console.WriteLine("Done!")
        Console.ReadLine()
    End Using
Catch timeProblem As TimeoutException
    Console.WriteLine("The service operation timed out. " & timeProblem.Message)
    Console.ReadLine()
    wcfClient.Abort()
Catch commProblem As CommunicationException
    Console.WriteLine("There was a communication problem. " & commProblem.Message)
    Console.ReadLine()
    wcfClient.Abort()
End Try

Endereço do ponto de extremidade em metadados

Um endereço de ponto de extremidade é representado no WSDL (Linguagem de Descrição dos Serviços Web) como um elemento de WS-Addressing EndpointReference (EPR) dentro do elemento wsdl:port do ponto de extremidade correspondente. O EPR contém o endereço do ponto de extremidade, bem como quaisquer propriedades de endereço. Observe que a EPR dentro de wsdl:port substitui soap:Address conforme pode ser visto no exemplo a seguir.

Definindo endereços de ponto de extremidade no código

Um endereço de ponto de extremidade pode ser criado no código com a classe EndpointAddress. O URI especificado para o endereço do ponto de extremidade pode ser um caminho totalmente qualificado ou um caminho relativo ao endereço base do serviço. O código a seguir ilustra como criar uma instância da classe EndpointAddress e adicioná-la à instância ServiceHost que está hospedando o serviço.

O exemplo a seguir demonstra como especificar o endereço completo do ponto de extremidade no código.

Uri baseAddress = new Uri("http://localhost:8000/HelloService");
string address = "http://localhost:8000/HelloService/MyService";

using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
    serviceHost.AddServiceEndpoint(typeof(IHello), new BasicHttpBinding(), address);
    serviceHost.Open();
    Console.WriteLine("Press <enter> to terminate service");
    Console.ReadLine();
    serviceHost.Close();
}

O exemplo a seguir demonstra como adicionar um endereço relativo ("MyService") ao endereço base do host de serviço.

Uri baseAddress = new Uri("http://localhost:8000/HelloService");

using (ServiceHost serviceHost = new ServiceHost(typeof(HelloService), baseAddress))
{
    serviceHost.AddServiceEndpoint(typeof(IHello), new BasicHttpBinding(), "MyService");
    serviceHost.Open();
    Console.WriteLine("Press <enter> to terminate service");
    Console.ReadLine();
    serviceHost.Close();
}

Observação

As propriedades de ServiceDescription do aplicativo de serviço não devem ser modificadas posteriormente para o método OnOpening em ServiceHostBase. Alguns membros, como a propriedade Credentials e os métodos AddServiceEndpoint em ServiceHostBase e ServiceHost, lançam uma exceção se modificados após esse ponto. Outros permitem modificá-los, mas o resultado é indefinido.

Da mesma forma, no cliente, os valores ServiceEndpoint não devem ser modificados após a chamada para OnOpening no ChannelFactory. A propriedade Credentials gera uma exceção se modificada após esse ponto. Os outros valores de descrição do cliente podem ser modificados sem erro, mas o resultado é indefinido.

Seja para o serviço ou cliente, é recomendável modificar a descrição antes de chamar Open.

Usando pontos de extremidade padrão

Se nenhum ponto de extremidade for especificado no código ou na configuração, o runtime fornecerá pontos de extremidade padrão adicionando um ponto de extremidade padrão em cada endereço base para cada contrato de serviço implementado pelo serviço. O endereço básico pode ser especificado no código ou na configuração, e os pontos de extremidade padrão são adicionados quando Open são chamados no ServiceHost.

Se os pontos de extremidade forem fornecidos explicitamente, os pontos de extremidade padrão ainda poderão ser adicionados chamando AddDefaultEndpoints no ServiceHost antes de chamar Open. 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.

Confira também