Partager via


Spécification d'une adresse de point de terminaison

Toute communication avec un service WCF (Windows Communication Foundation) s’effectue par l’intermédiaire de ses points de terminaison. Chaque ServiceEndpoint contient un Address, un Binding et un Contract. Le contrat spécifie quelles opérations sont disponibles. La liaison spécifie comment communiquer avec le service et l’adresse spécifie où rechercher le service. Chaque point de terminaison doit avoir une adresse unique. L’adresse de point de terminaison est représentée par la classe EndpointAddress, qui contient un URI (Uniform Resource Identifier) représentant l’adresse du service, un Identity représentant l’identité de sécurité du service et une collection de Headers facultative. Les en-têtes facultatifs fournissent des informations d'adressage plus détaillées pour identifier ou interagir avec le point de terminaison. Par exemple, les en-tête peuvent indiquer comment traiter un message entrant, où le point de terminaison doit envoyer un message de réponse ou quelle instance d'un service utiliser pour traiter un message entrant d'un utilisateur particulier lorsque plusieurs instances sont disponibles.

Définition d'une adresse de point de terminaison

Dans WCF, un EndpointAddress modélise une référence de point de terminaison (EPR) comme défini dans la norme WS-Addressing.

L'URI d'adresse de la plupart des transports se compose de quatre parties. Par exemple, l’URI http://www.fabrikam.com:322/mathservice.svc/secureEndpoint comporte les quatre parties suivantes :

  • Schéma : http:

  • Machine : www.fabrikam.com

  • (Facultatif) Port : 322

  • Chemin d’accès : /mathservice.svc/secureEndpoint

Une partie du modèle ERP établit que chaque référence de point de terminaison peut contenir des paramètres de référence qui ajoutent des informations d'identification supplémentaires. Dans WCF, ces paramètres de référence sont modélisés sous forme d’instances de la classe AddressHeader.

L'adresse du point de terminaison pour un service peut être spécifiée de manière impérative en utilisant le code ou de façon déclarative par la configuration. La définition de points de terminaison dans le code est généralement peu pratique car les liaisons et les adresses pour un service déployé sont en général différentes de celles utilisées au cours du développement du service. En général, il est plus pratique de définir des points de terminaison de service à l'aide de la configuration plutôt que du code. Le fait de conserver les informations de liaison et d'adressage hors du code leur permet de changer sans devoir recompiler ou de redéployer l'application. Si aucun point de terminaison n'est spécifié dans le code ou dans la configuration, le runtime ajoute un point de terminaison par défaut sur chaque adresse de base pour chaque contrat implémenté par le service.

Il y a deux façons de spécifier des adresses de point de terminaison pour un service dans WCF. Vous pouvez spécifier une adresse absolue pour chaque point de terminaison associé au service ou vous pouvez fournir une adresse de base pour le ServiceHost d'un service puis spécifier une adresse pour chaque point de terminaison associé à ce service défini comme relatif à cette adresse de base. Vous pouvez utiliser chacune de ces procédures pour spécifier les adresses de point de terminaison pour un service dans la configuration ou le code. Si vous ne spécifiez pas d'adresse relative, le service utilise l'adresse de base. Vous pouvez également avoir plusieurs adresses de base pour un service, mais une seule adresse de base pour chaque transport est autorisée pour chaque service. Si vous avez plusieurs points de terminaison, chacun configuré avec une liaison différente, leurs adresses doivent être uniques. Les points de terminaison qui utilisent la même liaison mais des contrats différents peuvent utiliser la même adresse.

Lorsque vous hébergez avec les services IIS, vous ne gérez pas l'instance ServiceHost vous-même. L'adresse de base est toujours l'adresse spécifiée dans le fichier .svc pour le service lors de l'hébergement dans IIS. Par conséquent, vous devez toujours utiliser des adresses de point de terminaison relatives pour les points de terminaison de service hébergés dans IIS. Fournir une adresse de point de terminaison qualifiée complète peut entraîner des erreurs lors du déploiement du service. Pour plus d’informations, consultez Déploiement d’un service WCF hébergé dans Internet Information Services.

Définition des adresses de point de terminaison dans la configuration

Pour définir un point de terminaison dans un fichier de configuration, utilisez l’élément <endpoint>.

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

Lorsque la méthode Open est appelée (c’est-à-dire, lorsque l’application d’hébergement essaie de démarrer le service), le système recherche un élément <service> avec un attribut de nom qui spécifie « UE.Samples.HelloService ». Si l’élément <service> est trouvé, le système charge la classe spécifiée et crée des points de terminaison à l’aide des définitions de point de terminaison fournies dans le fichier de configuration. Ce mécanisme vous permet de charger et de démarrer un service avec deux lignes de code tout en laissant la liaison et les informations d’adressage hors de votre code. L'avantage de cette approche est que ces modifications peuvent être apportées sans devoir recompiler ou redéployer l'application.

Les en-têtes facultatifs sont déclarés dans un élément <headers>. Vous trouverez ci-dessous un exemple des éléments utilisés pour spécifier des points de terminaison pour un service dans un fichier de configuration qui fait la distinction entre deux en-tête : clients « Gold » de http://tempuri1.org/ et clients « Standard » de http://tempuri2.org/. Le client appelant ce service doit avoir l’élément <headers> approprié dans son fichier de configuration.

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

Les en-tête peuvent également être définis sur les messages individuels au lieu de tous les messages sur un point de terminaison (comme montré précédemment). Pour cela, vous devez utiliser OperationContextScope pour créer un nouveau contexte dans une application cliente afin d'ajouter un en-tête personnalisé au message sortant, comme illustré dans l'exemple suivant.

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

Adresse de point de terminaison dans les métadonnées

Une adresse de point de terminaison est représentée dans WSDL (Web Services Description Language) comme un élément EndpointReference (EPR) WS-Addressing dans l'élément wsdl:port du point de terminaison correspondant. L'EPR contient l'adresse du point de terminaison ainsi que toutes les propriétés d'adresse. Notez que l'EPR à l'intérieur de wsdl:port remplace soap:Address comme dans l'exemple suivant.

Définition d'adresses de point de terminaison dans le code

Une adresse de point de terminaison peut être créée dans le code avec la classe EndpointAddress. L’URI spécifié pour l’adresse de point de terminaison peut être un chemin d’accès qualifié complet ou un chemin d’accès qui est relatif à l’adresse de base du service. L'exemple de code suivant illustre la création d'une nouvelle instance de la classe EndpointAddress et son ajout à l'instance ServiceHost qui héberge le service.

L'exemple suivant montre comment spécifier l'adresse de point de terminaison complète dans le code.

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

L'exemple suivant montre comment ajouter une adresse relative ("MyService") à l'adresse de base de l'hôte de service.

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

Notes

Les propriétés de ServiceDescription dans l'application de service ne doivent pas être modifiées à l'issue de la méthode OnOpening sur ServiceHostBase. Certains membres, tels que la propriété Credentials et les méthodes AddServiceEndpoint sur ServiceHostBase et ServiceHost, lèvent une exception s'ils sont modifiés au-delà de ce point. D'autres membres peuvent être modifiés, mais le résultat n'est pas défini.

De la même façon, sur le client les valeurs ServiceEndpoint ne doivent pas être modifiées après l'appel à OnOpening sur ChannelFactory. La propriété Credentials lève une exception si elle est modifiée au-delà de ce point. Les autres valeurs de description du client peuvent être modifiées sans erreur, mais le résultat n'est pas défini.

Aussi bien pour le service que le client, il est recommandé de modifier la description avant d'appeler Open.

Utilisation des points de terminaison par défaut

Si aucun point de terminaison n'est spécifié dans le code ou dans la configuration, le runtime fournit les points de terminaison par défaut en ajoutant un point de terminaison par défaut sur chaque adresse de base pour chaque contrat de service implémenté par le service. L'adresse de base peut être spécifiée dans le code ou dans la configuration, et les points de terminaison par défaut sont ajoutés lors de l'appel de Open sur le ServiceHost.

Si des points de terminaison sont fournis explicitement, les points de terminaison par défaut peuvent toujours être ajoutés en appelant AddDefaultEndpoints sur le ServiceHost avant d'appeler Open. Pour plus d’informations sur les points de terminaison, les liaisons et les comportements par défaut, consultez Configuration simplifiée et Configuration simplifiée pour les services WCF.

Voir aussi