web-dev-qa-db-fra.com

Configuration de WCF TCP dans une application Web

Je me bats avec cela depuis des jours, parcourant littéralement une centaine d'articles donnant des directives partielles sur la façon de configurer un service basé sur WCF TCP dans une application Web. Si quelqu'un peut m'aider, je fera de cette question une directive complète .

État actuel

La connexion net.tcp fonctionne sur ma machine de développement. Il fonctionne également localement après avoir été déployé sur un serveur Windows Server 2008 R2. Cependant, cela ne fonctionne pas à distance, même s'il est possible de se connecter au port 808 sur le serveur à distance. Faites défiler vers le bas de la question pour plus de détails. S'il vous plait aidez si vous le pouvez.

Je vais créer une nouvelle question pour ce détail et mettre à jour cette question avec la réponse si j'en tire un résultat.

Code

J'ai créé ServerHubService.svc avec le contenu suivant:

namespace Manage.SignalR
{
    [ServiceContract]
    public class ServerHubService
    {
        [OperationContract]
        public void UpdateServerStatus(string serverStatus)
        {
            // Do something
        }
    }
}

Configuration de l'application hébergeant le service

Après un tutoriel en ligne, j'ai ajouté ce qui suit à mon Web.config (j'ai essayé BEAUCOUP de variantes différentes). Il s'agit du Web.config de l'application Web hébergeant le service auquel je souhaite plus tard me connecter avec TCP.

<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="ServerHubBehavior"
      name="Manage.SignalR.ServerHubService">
        <endpoint address=""
              binding="netTcpBinding"
              bindingConfiguration="portSharingBinding"
              name="MyServiceEndpoint"
              contract="Manage.SignalR.ServerHubService">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>

        <endpoint address="mex"
              binding="mexTcpBinding"
              bindingConfiguration=""
              name="MyServiceMexTcpBidingEndpoint"
              contract="IMetadataExchange" />
        <Host>
          <baseAddresses>
            <add baseAddress="net.tcp://test.mydomain.com:808/SignalR/ServerHubService.svc" />
          </baseAddresses>
        </Host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServerHubBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="portSharingBinding" portSharingEnabled="true"/>
      </netTcpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
      minFreeMemoryPercentageToActivateService="0" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
</configuration>

httpGetEnabled="true" est important car sinon vous ne pouvez pas créer une référence de service au service.

Configuration du serveur sur lequel l'application Web s'exécute

Je configure ceci sur ma machine de développement qui a IIS 7.5

J'ai lu que IIS Express (intégré à Visual Studio) ne prend pas en charge net.tcp, j'ai donc configuré un nouveau site Web en IIS 7.5 à l'aide de .NET 4.5 et qui a une liaison net.tcp

bindings in IIS

Je suis également allé dans les paramètres avancés du site Web et j'ai défini les protocoles activés sur http,net.tcp

Je me suis assuré que l'activation non HTTP de la fonctionnalité Windows est activée (et redémarrée). C'est une fonctionnalité Windows, alors recherchez "Activer ou désactiver les fonctionnalités Windows" pour le trouver.

enter image description here

Confirmation de l'exécution de l'application Web

Le site Web fonctionne bien pour le reste de l'application Web. J'ai configuré test.mydomain.com pour pointer vers 127.0.0.1 dans mon fichier hosts. Je peux même visiter http://test.mydomain.com/SignalR/ServerHubService.svc et il me montrera une belle page générée automatiquement à partir de .NET, expliquant comment utiliser ce service.

Jusqu'ici tout va bien.

La page générée par .NET me dit d'utiliser cette adresse pour générer une connexion à mon service:

net.tcp://computername/SignalR/ServerHubService.svc/mex

Essayer de se connecter au service en tant que client

Si vous ne pensez pas à définir httpGetEnabled="true" vous obtiendrez une erreur en essayant de lui créer une référence de service. Si vous utilisez le client de test WCF (également un outil inclus dans Visual Studio) et n'avez pas défini httpGetEnabled, vous obtiendrez une erreur comme celle-ci:

Erreur: impossible d'obtenir les métadonnées à partir de net.tcp: //computername/SignalR/ServerHubService.svc/mex

S'il s'agit d'un service Windows (R) Communication Foundation auquel vous avez accès, veuillez vérifier que vous avez activé la publication des métadonnées à l'adresse spécifiée. Pour obtenir de l'aide sur l'activation de la publication des métadonnées, reportez-vous à la documentation MSDN sur http://go.Microsoft.com/fwlink/?LinkId=65455.WS-Metadata

URI d'erreur Exchange: net.tcp: //computername/SignalR/ServerHubService.svc/mex Les métadonnées contiennent une référence qui ne peut pas être résolue: 'net.tcp: //computername/SignalR/ServerHubService.svc/mex'. Impossible de se connecter à net.tcp: //computername/SignalR/ServerHubService.svc/mex. La tentative de connexion a duré 00: 00: 04.0032289.

Code d'erreur TCP 10061: Aucune connexion n'a pu être établie car la machine cible l'a activement refusée [2001: 0: 4137: 9e76: c81: a4c: a547: b2fd]: 808. Aucune connexion n'a pu être établie car la machine cible l'a activement refusée [2001: 0: 4137: 9e76: c81: a4c: a547: b2fd]: 808

Cependant, si vous avez tout fait comme ci-dessus, vous devriez pouvoir ajouter une référence au service.

Méthodes d'appel dans le service

Lorsque vous essayez d'appeler une méthode Hello World simple dans le service à partir du client de test WCF, elle renvoie l'erreur suivante:

Impossible de se connecter à net.tcp: //computername/SignalR/ServerHubService.svc. La tentative de connexion a duré pendant une période de 00: 00: 04.0002288. TCP code d'erreur 10061: aucune connexion n'a pu être établie car la machine cible l'a activement refusée.

Il s'agit de la trace de pile interne incluse avec l'erreur:

Aucune connexion n'a pu être établie car la machine cible l'a activement refusée [2001: 0: 5ef5: 79fb: 3884: a: a547: b2fd]: 808 sur System.Net.Sockets.Socket.DoConnect (EndPoint endPointSnapshot, SocketAddress socketAddress) sur System .Net.Sockets.Socket.Connect (EndPoint remoteEP) sur System.ServiceModel.Channels.SocketConnectionInitiator.Connect (Uri uri, TimeSpan timeout)

Si tu utilises netstat -an |find /i "listening" pour voir que rien n'écoute sur le port 808, c'est probablement parce que le service Net.Tcp Listener Adapter n'est pas en cours d'exécution.

Confirmation

L'appel est en cours maintenant, mais une confirmation est nécessaire avant qu'il ne puisse être déclaré réussi. Je dois confirmer qu'il s'agit en fait d'un appel net.tcp sur le port 808 et non d'un appel sur le point de terminaison http. J'essaie de le faire avec Wireshark, mais cela ne s'affiche pas, probablement parce que c'est un appel qui passe de et vers ma machine locale.

Déploiement

Le dernier défi à relever serait de le déployer sur un serveur Web, en s'assurant que ce qui fonctionne sur la machine de développement, fonctionne également sur le serveur Web.

Cela ne fonctionne pas après la publication sur Windows Server 2008 R2. Il donne le commun SocketException: An existing connection was forcibly closed by the remote Host.

Il fonctionne bien localement sur le serveur, mais il ne fonctionne pas à distance.

Voici la liste de contrôle utilisée pour vérifier le serveur:

  • Est le Net.Tcp Listener Adapter service en cours? Oui
  • Le site IIS est-il lié à net.tcp mis à 808:*? Oui
  • Les protocoles activés sont-ils sous Paramètres avancés pour le site dans IIS défini sur http,net.tcp? Oui
  • Le serveur écoute-t-il sur le port 808? Oui, vérifié avec netstat -an |find /i "listening"
  • Un port 808 est-il ouvert dans le pare-feu? Oui.
    • Le pare-feu est désactivé sur le serveur.
    • Je peux telnet au serveur sur le port 808 de l'extérieur avec telnet mydomain.com 808
  • Dans la configuration du service sur le serveur, les éléments suivants ont été confirmés:
    • baseAddress est ajusté à net.tcp://mydomain.com:808/SignalR/ServerHubService.svc
    • C'était localhost avant, mais changé en mydomain.com après que cela n'a pas fonctionné sur le serveur: <identity><dns value="mydomain.com" /></identity>
  • Il a été testé avec un client localement sur le serveur et sur un autre serveur. Les deux peuvent se connecter au port 808 avec telnet et tous deux donnent le même message d'erreur.

Quelle configuration pourrait manquer sur le serveur? Je suis si proche du but. Veuillez m'aider à résoudre ce problème et à répondre à la question.

Voici la configuration client sur le serveur appelant le service:

<system.serviceModel>
  <bindings>
    <netTcpBinding>
      <binding name="MyServiceEndpoint" />
    </netTcpBinding>
  </bindings>
  <client>
    <endpoint address="net.tcp://mydomain.com:808/SignalR/ServerHubService.svc"
      binding="netTcpBinding" bindingConfiguration="MyServiceEndpoint"
      contract="ServerHubService.ServerHubService" name="MyServiceEndpoint">
      <identity>
        <dns value="mydomain.com" />
      </identity>
    </endpoint>
  </client>
</system.serviceModel>

J'ai également essayé sans 808 configuré dans le point de terminaison, car cela serait le port par défaut pour les connexions net.tcp. Cependant, cela donne toujours le même résultat.

Au lieu d'essayer beaucoup de choses au hasard, la bonne question est peut-être: comment déboguer quelque chose comme ça? Puis-je installer un programme sur l'un ou l'autre des serveurs qui me dira exactement POURQUOI cet appel est bloqué?

Avec Wireshark configuré comme ceci, il est possible de regarder l'appel entrant sur le serveur sur le port 808 et de déterminer éventuellement pourquoi l'appel ne fonctionne pas. Cependant, je ne sais pas comment analyser cela à l'heure actuelle.

wireshark

Bonne chance

J'ai abandonné et mis en œuvre cela dans la couche socket à la place. Cela a fonctionné immédiatement. J'espère que cela peut aider quelqu'un d'autre. Je mets une réponse parce que beaucoup de problèmes ont été résolus et cela a finalement fonctionné localement, donc tout problème restant est probablement lié à mon environnement spécifique.

29
Niels Brinch

Vous devez générer le proxy en fonction des métadonnées exposées sur HTTP pour tcp (assurez-vous que httpGetEnabled est défini sur true). L'adresse que vous utilisez chez le client doit être l'adresse hébergée. Veuillez vous référer au post ci-dessous.

http://blogs.msdn.com/b/swiss_dpe_team/archive/2008/02/08/iis-7-support-for-non-http-protocols.aspx

7
Prasath

Dans votre question, vous avez mentionné que vous vous êtes connecté à "test.mydomain.com" mais l'erreur a changé le serveur en "nom_ordinateur". Ensuite, dans votre commentaire, vous avez mentionné qu'il ne parvenait toujours pas à se connecter. Si vous souhaitez que l'alias soit renvoyé dans WSDL/MEX, ajoutez le nœud useRequestHeadersForMetadataAddress dans votre comportement de service. Voici les informations MSDN sur ce nœud: nœud MSDN useRequestHeadersForMetadataAddress

Voici à quoi devrait ressembler votre configuration. Cela prend en compte la réponse donnée par Prasath (httpGetEnabled = "true").

<serviceBehaviors>
   <behavior name="ServerHubBehavior">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
      <useRequestHeadersForMetadataAddress>
         <defaultPorts>
            <add scheme="net.tcp" port="808" />
         </defaultPorts>
      </useRequestHeadersForMetadataAddress>
   </behavior>
</serviceBehaviors>
2
J Man

Avez-vous essayé d'héberger le service (à des fins de test) dans un service Windows sur votre ordinateur local? De cette façon, vous saurez au moins si le problème est du côté service ou s'il s'agit d'une configuration IIS/serveur.

0
mez

J'ai eu un problème similaire ici aujourd'hui, lors de l'appel d'un service wcf net.tcp à partir d'une API web asp.net. Je ne dirai pas qu'à partir de toutes les autres machines, ce service fonctionne depuis des années, mais les appels ont été effectués en auto-hébergement wcf, en hébergement de compatibilité wcf iis asp.net -> contre le service net.tcp auto-hébergé. Quand j'ai ensuite publié mon API Web simple appelant le même service net.tcp, tout s'est mal passé et toute la connexion a été abandonnée sans aucune raison, même le wcf complet retraçant les deux côtés (service et client) n'a pas aidé, en disant simplement la même chose msgstr "connexion interrompue".

Je savais déjà que net.tcp est livré avec la sécurité sur le transport activée, en utilisant l'authentification Windows pour signer et crypter la communication, alors j'ai juste essayé de désactiver la sécurité et tout commence à fonctionner correctement.

Essayez simplement de désactiver la sécurité de cette façon des deux côtés (client et service):

<security mode="None"/>

liaison de service complet:

<netTcpBinding>

    <binding name="netTcpBinding" portSharingEnabled="true">

        <security mode="None"/>

    </binding>

</netTcpBinding>

J'espère que cela peut aussi vous aider.

0
Michael Denny

Vous avez service de partage de port Net.TCP en cours d'exécution sur le serveur, je suppose ... ne l'avez pas trouvé explicitement indiqué.

0
Nicolai Ustinov

Je suppose que le problème que vous rencontrez est que vous devez configurer le SPN (Service Principal Name) pour votre service WCF (sur la machine) et le faire ajouter au compte de service sous lequel le service s'exécute.

Si vous l'exécutez sous l'utilisateur du pool d'applications par défaut, vous devez configurer le SPN pour la machine.

Je sais que c'est troublant, et c'est généralement la surprise qui attend nos développeurs une fois que notre service est prêt à être déployé dans des environnements de production ou de pré-production.

Le SPN est utilisé par Kerberos pendant le processus d'authentification.

Essayez d'utiliser l'IP de la machine pour résoudre votre service au lieu du nom d'hôte. (Ce n'est pas censé nécessiter un SPN), remplacez "test.mydomain.com" par l'adresse IP de la machine:

<Host>
    <baseAddresses>
        <add baseAddress="net.tcp://192.168.0.253:808/SignalR/ServerHubService.svc" />
    </baseAddresses>
</Host>

Jetez un œil à ces articles: - Kerberos pour l'administrateur occupé
- WCF sur intranet avec authentification Windows
- Pour le message suivant, essayez de lire celui qui n'est pas accepté comme réponse: Quel SPN dois-je définir pour un service net.tcp?

0
Ashraf ElSwify

Hébergement d'un TCP basé sur IIS a toujours été un ours. WCF facilite très facilement l'exécution de votre propre hôte de service, en écoutant sur votre TCP. Ma recommandation serait de le faire et de le configurer pour qu'il fonctionne en tant que service Windows.

Voir cet article: http://msdn.Microsoft.com/en-us/library/ff649818.aspx

0
Mike Pugh