Mise en place du service TCP WCF dans une application web
j'ai lutté avec cela pendant des jours, en parcourant littéralement une centaine d'articles donnant des directives partielles sur la façon de mettre en place un service basé sur TCP WCF dans une application web. Si quelqu'un peut m'aider, je ferai de cette question une ligne directrice complète .
état Actuel
sur Le net.connexion tcp fonctionne sur ma machine de développement. Il fonctionne également localement après avoir été déployé dans un Windows Server 2008 R2. Cependant, il ne fonctionne pas à distance, même s'il est possible de telnet au port 808 sur le serveur à distance. Faites défiler vers le bas de la question pour plus de détails. S'il vous plaît aider 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'obtiens 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
suite à un tutoriel en ligne, j'ai ajouté ce qui suit à mon site web.config (j'ai essayé plusieurs variantes). C'est le Web.config de l'application Web hébergeant le service que je veux plus tard 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 parce que sinon vous ne pouvez pas créer une référence de service à service.
Configuration du serveur où l'application web est en cours d'exécution
je mets en place ce sur ma machine de développement qui a IIS 7.5
j'ai lu que IIS Express (construit dans Visual Studio) ne supporte pas net.tcp, donc j'ai mis en place un nouveau site Web dans IIS 7.5 en utilisant .NET 4.5 et qui a un réseau.tcp liaison
je suis également allé à des paramètres avancés pour le site web et les Protocoles activés de http,net.tcp
j'ai veillé à ce que la fonctionnalité Windows Non-Activation HTTP soit activée (et redémarrée). C'est une Fonctionnalité de Windows donc chercher des "fonctionnalités Windows Activer ou désactiver" pour trouver cela.
confirmation que l'application web est en cours d'exécution
le site fonctionne très bien pour le reste de l'application web. J'installe test.mydomain.com 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.
pour l'instant 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 vous souvenez pas de mettre httpGetEnabled="true"
vous obtiendrez une erreur en essayant de créer une référence de service à elle. Si vous utilisez le Client Test de la WCF (également un outil inclus dans Visual Studio) et que vous n'avez pas configuré httpGetEnabled, vous obtiendrez une erreur du type:
erreur: Impossible d'obtenir des métadonnées de net.tcp://nom de l'ordinateur/SignalR/ServerHubService.svc / mex
S'il s'agit D'un service de la Fondation Windows (R) Communication auquel vous avoir 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 pour la publication de métadonnées, veuillez reportez-vous à la documentation du MSDN à l'adresse suivante: http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata
erreur D'échange URI: net.tcp://nom de l'ordinateur/SignalR/ServerHubService.métadonnées svc/mex contient une référence qui ne peut être résolue: 'net.tcp://nom de l'ordinateur/SignalR/ServerHubService.svc / mex". Ne pouvait pas se connecter au net.tcp://nom de l'ordinateur/SignalR/ServerHubService.svc / mex. La tentative de connexion a duré pendant une période de temps de 00:00: 04.0032289.
code D'erreur TCP 10061: aucune connexion n'a pu être établie car la cible machine a activement refusé [2001:0:4137:9e76:c81:a4c:a547: b2fd]: 808. Aucune connexion n'a pu être établie car l'ordinateur cible activement refusé [2001: 0: 4137:9e76:c81:a4c:a547:b2fd]: 808
cependant, si vous avez fait tout comme ci-dessus, vous devriez être en mesure d'ajouter une référence au service.
l'Appel de méthodes dans le service
en essayant d'appeler une méthode Hello World simple dans le service du Client de Test de la WCF, il renvoie le suivant erreur:
ne pouvait pas se connecter à net.tcp://nom de l'ordinateur/SignalR/ServerHubService.svc. Connexion la tentative a duré pendant une période de temps de 00:00: 04.0002288. TCP code d'erreur 10061: Aucune connexion n'a pu être établie car l'ordinateur cible activement l'a refusé.
c'est le stactrace intérieur qui est inclus dans avec l'erreur:
aucune connexion n'a pu être établie parce que la cible la machine activement refusé [2001:0:5ef5:79fb:3884:: a547:b2fd]:808 à Système.Net.Douilles.Socket.DoConnect(EndPoint endPointSnapshot), SocketAddress socketAddress) Système.Net.Douilles.Socket.Connect (EndPoint remoteEP) à Système.ServiceModel.Canal.SocketConnectionInitiator.Connect (Uri) uri, plage de Temps (timeout)
si vous utilisez netstat -an |find /i "listening"
pour voir que rien n'écoute sur le port 808, c'est probablement parce que le Net.Adaptateur D'Écoute Tcp le service n'est pas en cours d'exécution.
Confirmation
l'appel est passé maintenant, mais une certaine confirmation est nécessaire avant qu'il puisse être déclaré un succès. Je dois confirmer que c'est en fait net.tcp appelle sur le port 808 et pas vraiment un appel sur le terminal http. J'essaie de faire ça avec Wireshark, mais ça ne se voit pas, probablement parce que c'est un appel de et Vers ma machine locale.
déploiement
le dernier défi à relever serait de déployer cela sur un serveur web, en s'assurant que ce qui fonctionne sur la machine de développement, fonctionne aussi sur le serveur web.
il ne fonctionne pas après publier sur un serveur Windows 2008 R2. Il donne le commun SocketException: An existing connection was forcibly closed by the remote host
.
fonctionne bien localement sur le serveur, mais ne fonctionne pas à distance.
Voici la liste de contrôle utilisée pour vérifier le serveur:
- est-ce que le service
Net.Tcp Listener Adapter
fonctionne? Oui - le site de L'IIS est-il lié à
net.tcp
par808:*
? Oui - est activé protocoles sous Paramètres avancés pour le site dans IIS réglé à
http,net.tcp
? Oui - est-ce que le serveur écoute sur le port 808? Oui, vérifié avec
netstat -an |find /i "listening"
- est-ce qu'un port 808 est 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, ce qui suit a été confirmé:
- baseAddress est ajusté à
net.tcp://mydomain.com:808/SignalR/ServerHubService.svc
- c'était
localhost
avant, mais changé enmydomain.com
après il n'a pas travail sur le serveur:<identity><dns value="mydomain.com" /></identity>
- baseAddress est ajusté à
- 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 donnent le même message d'erreur.
quelle configuration pourrait manquer sur le serveur? Je suis si près du but. Veuillez m'aider à résoudre ce problème et répondre à la question.
voici le client configuration 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 l'endpoint, car c'est le port par défaut pour net.les connexions tcp. Cependant, il 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 cela? puis-je installer un programme sur l'un ou l'autre serveur qui me dira exactement pourquoi cet appel est bloqué?
avec Wireshark configuré comme ceci, il est possible de regarder l'appel venant au serveur sur le port 808 et éventuellement de déterminer pourquoi l'appel ne fonctionne pas. Cependant, je n'ai aucune idée de comment analyser ce à l'heure actuelle.
bonne chance
j'ai abandonné et implémenté ceci dans la couche socket à la place. Il a travaillé immédiatement. J'espère que cela peut aider quelqu'un d'autre. Je mets en place une réponse parce que beaucoup des problèmes ont été résolus et cela a finalement fonctionné localement, donc tout problème restant est probablement lié à mon environnement spécifique.
7 réponses
vous devez générer le Proxy basé sur les métadonnées exposées sur HTTP pour tcp.(assurez-vous que httpGetEnabled est défini à true). L'adresse que vous utilisez à la clientèle doit être hébergés adresse. Veuillez consulter ci-dessous post.
http://blogs.msdn.com/b/swiss_dpe_team/archive/2008/02/08/iis-7-support-for-non-http-protocols.aspx
dans votre question vous avez mentionné que vous vous êtes connecté à "test.mydomain.com" mais l'erreur a changé le serveur en "computername". Puis dans votre commentaire vous avez mentionné qu'il ne se connecte toujours pas. Si vous souhaitez que l'alias soit retourné dans le fichier WSDL/MEX, ajoutez le noeud userequestheadersformetadata dans votre comportement de service. Voici les informations MSDN sur ce noeud: MSDN useRequestHeadersForMetadataAddress noeud
voici comment votre config devrait regarder. Cela tient compte de 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>
héberger un service basé sur TCP dans IIS a toujours été un ours. WCF rend très facile l'exécution de votre propre hôte de service, en écoutant sur votre port TCP. Ma recommandation serait de le faire et de le configurer pour qu'il fonctionne comme un service Windows.
voir cet article: http://msdn.microsoft.com/en-us/library/ff649818.aspx
je suppose que le problème que vous rencontrez est que vous devez configurer le SPN (nom Principal du Service) pour votre service FMC (sur la machine) et le faire ajouter au compte de service sous lequel le service est exécuté.
si vous l'exécutez sous l'utilisateur par défaut de l'application pool, alors vous devez avoir le SPN configuré pour la machine.
je sais qu'il est troublant, et est typiquement la surprise qui attend de nous devs une fois que notre service est prêt à déployer 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. (Ceci n'est pas censé exiger un SPN), remplacer "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>
regardez ces articles:
- Kerberos pour L'administrateur occupé
- WCF sur intranet avec authentification windows
- Pour le post suivant, essayer de lire celui qui n'est pas accepté comme une réponse: ce SPN que je dois mettre pour un filet.service tcp?
avez-vous essayé d'héberger le service (à des fins de test) dans un service Windows sur votre machine locale? De cette façon, vous saurez au moins si le problème est du côté du service ou si c'est la configuration IIS/server.
vous avez Net.Service de partage de ports TCP tournant sur le serveur je suppose... n'ont pas trouvé explicitement mentionnés.
j'ai eu un problème similaire ici aujourd'hui, en appelant un filet.tcp WCF service de l'intérieur d'un asp.net Web api. Je ne dirai pas que de toutes les autres machines ce service a fonctionné pendant des années, mais les appels ont été faits WCF auto hébergement, wcf iis asp.net compatibilité hébergement - > contre le net.service tcp auto-hébergé. Quand j'ai publié mon api web simple appelant le même réseau.le service tcp, tout est allé de Travers, et toute la connexion a été interrompue sans aucune raison, même la wcf complète le fait de retracer les deux parties (le service et le client) n'a pas aidé, mais simplement de dire que la même "connexion a été interrompue".
j'ai déjà connu ce net.tcp est livré avec la sécurité sur le transport activé, en utilisant l'authentification windows pour signer et crypter la communication, si bien, je viens d'essayer d'éteindre 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"/>
full service de liaison:
<netTcpBinding>
<binding name="netTcpBinding" portSharingEnabled="true">
<security mode="None"/>
</binding>
</netTcpBinding>
j'espère que cela pourra vous aider aussi.