Question

I've been battling with this for days, literally going through a hundred articles giving partial guidelines on how to set up a WCF TCP based service in a web application. If someone can help me, I will make this question into a complete guideline.

Current status

The net.tcp connection works on my development machine. It also works locally after being deployed to a Windows Server 2008 R2. However, it doesn't work remotely, even though it's possible to telnet to port 808 on the server remotely. Scroll to the bottom of the question for details. Please help if you can.

I will create a new question for this detail and update this question with the answer if I get a result out of it.

Code

I created ServerHubService.svc with the following content:

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

Configuration of the application hosting the service

Following an online tutorial, I added the following to my Web.config (I tried MANY different variations). This is the Web.config of the web application hosting the service that I later want to connect to with 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" is important because otherwise you cannot create a service reference to the service.

Configuration of the server where the web application is running

I am setting this up on my development machine which has IIS 7.5

I read that IIS Express (built into Visual Studio) doesn't support net.tcp, so I set up a new website in IIS 7.5 using .NET 4.5 and that has a net.tcp binding

bindings in IIS

I also went to Advanced Settings for the website and set Enabled Protocols to http,net.tcp

I ensured that the Windows Feature Non-HTTP Activation is enabled (and restarted). It's a Windows Feature so look for "Turn Windows features on or off" to find this.

enter image description here

Confirming the web application is running

The website works fine for the rest of the web application. I set up test.mydomain.com to point to 127.0.0.1 in my hosts file. I can even visit http://test.mydomain.com/SignalR/ServerHubService.svc and it will show me a nice auto generated page from .NET, explaining how to use this service.

So far so good.

The page generated by .NET tells me to use this address to generate a connection to my service:

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

Trying to connect to the service as a client

If you do not remember to set httpGetEnabled="true" you will get an error when trying to create a service reference to it. If you use the WCF Test Client (also a tool included in Visual Studio) and didn't set httpGetEnabled, you will get an error like the following:

Error: Cannot obtain Metadata from net.tcp://computername/SignalR/ServerHubService.svc/mex

If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address. For help enabling metadata publishing, please refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata

Exchange Error URI: net.tcp://computername/SignalR/ServerHubService.svc/mex Metadata contains a reference that cannot be resolved: 'net.tcp://computername/SignalR/ServerHubService.svc/mex'. Could not connect to net.tcp://computername/SignalR/ServerHubService.svc/mex. The connection attempt lasted for a time span of 00:00:04.0032289.

TCP error code 10061: No connection could be made because the target machine actively refused it [2001:0:4137:9e76:c81:a4c:a547:b2fd]:808. No connection could be made because the target machine actively refused it [2001:0:4137:9e76:c81:a4c:a547:b2fd]:808

However, if you've done everything as above, you should be able to add a reference to the service.

Calling methods in the service

When trying to call a simple Hello World method in the service from the WCF Test Client, it returns the following error:

Could not connect to net.tcp://computername/SignalR/ServerHubService.svc. The connection attempt lasted for a time span of 00:00:04.0002288. TCP error code 10061: No connection could be made because the target machine actively refused it.

This is inner stacktrace that is included in with the error:

No connection could be made because the target machine actively refused it [2001:0:5ef5:79fb:3884:a:a547:b2fd]:808 at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress) at System.Net.Sockets.Socket.Connect(EndPoint remoteEP) at System.ServiceModel.Channels.SocketConnectionInitiator.Connect(Uri uri, TimeSpan timeout)

If you use netstat -an |find /i "listening" to see that nothing is listening on port 808, it's probably because the Net.Tcp Listener Adapter service is not running.

Confirmation

The call goes through now, but some confirmation is needed before it can be declared a success. I need to confirm that this is in fact net.tcp call on port 808 and not actually a call on the http endpoint. I am trying to do this with Wireshark, but it doesn't show up, probably because it's a call happening from and to my local machine.

Deployment

The last challenge to conquer would be to deploy this on a web server, ensuring that what works on the development machine, also works on the web server.

It doesn't work after publish to a Windows Server 2008 R2. It gives the common SocketException: An existing connection was forcibly closed by the remote host.

It works well locally on the server, but it doesn't work remotely.

Here is the checklist used to check the server:

  • Is the Net.Tcp Listener Adapter service running? Yes
  • Is the IIS site binding to net.tcp set to 808:*? Yes
  • Is Enabled Protocols under Advanced Settings for the site in IIS set to http,net.tcp? Yes
  • Is the server listening on port 808? Yes, checked with netstat -an |find /i "listening"
  • Is a port 808 open in the firewall? Yes.
    • Firewall is turned off on the server.
    • I can telnet to the server on port 808 from outside with telnet mydomain.com 808
  • In the configuration of the service on the server, the following was confirmed:
    • baseAddress is adjusted to net.tcp://mydomain.com:808/SignalR/ServerHubService.svc
    • This was localhost before, but changed to mydomain.com after it didn't work on the server: <identity><dns value="mydomain.com" /></identity>
  • It has been tested with a client locally on the server and on another server. Both can connect to port 808 with telnet and both give the same error message.

What configuration could be missing on the server? I am so close to the goal. Please assist me in troubleshooting this and complete the question.

Here is the client configuration on the server calling the 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>

I also tried without 808 configured in the endpoint, as this is rumored to be the default port for net.tcp connections. However, it still gives the same result.

Instead of trying lots of things randomly, the good question is perhaps: How does one debug something like this? Can I install a program on either server that will tell me exactly WHY this call is being blocked?

With Wireshark configured like this, it's possible to look at the call coming to the server on port 808 and possibly determine why the call doesn't work. However, I have no idea how to analyze this at present time.

wireshark

Good luck

I gave up and implemented this in the socket layer instead. It worked immediately. I hope this can help someone else, though. I'm setting an answer because many of the issues were solved and it did work locally eventually, so any problem remaining is probably related to me specific environment.

Was it helpful?

Solution

You have to generate the Proxy based on the metadata exposed over HTTP for tcp.(make sure httpGetEnabled is set to true). The address you use at the client should be the hosted address. Please refer the below post.

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

OTHER TIPS

In your question you mentioned that you connected to "test.mydomain.com" but the error changed the server to "computername". Then in your comment you mentioned it still failing to connect. If you wish to have the alias returned in the WSDL/MEX Add the useRequestHeadersForMetadataAddress node in your service behavior. Here is the MSDN information on this node: MSDN useRequestHeadersForMetadataAddress node

This is how your config should look. This takes into account answer given by 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>

Hosting a TCP Based service in IIS has always been a bear. WCF makes it very easy to run your own service host, listening on your TCP port. My recommendation would be to do that and set it up to run as a Windows Service.

See this article: http://msdn.microsoft.com/en-us/library/ff649818.aspx

I am guessing the issue you are having is that you need to setup the SPN (Service Principal Name) for your WCF service (on the machine) and have it added to the service account under which the service is running.

If you are running it under the default app pool user, then you need to have the SPN configured for the machine.

I know it is troubling, and typically is the surprise waiting fro us devs once our service is ready to deploy to production or pre-production environments.

The SPN is used by Kerberos during the authentication process.

Try using the IP of the machine to resolve your service instead of the hostname. (This is not supposed to require an SPN), replace "test.mydomain.com" by the machine IP address:

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

Take a look at these articles: - Kerberos for the Busy Admin
- WCF on intranet with windows authentication
- For the following post, try to read the one that is not accepted as an answer: What SPN do I need to set for a net.tcp service?

Did you tried to host service (for the testing purpose) in a Windows service on your local machine? This way you will at least know if the problem is on the service side or it's IIS/server configuration.

You have Net.TCP Port sharing service running on the server I guess... haven't found it explicitely stated.

I had a similar problem here today, while calling a net.tcp wcf service from inside an asp.net web api. I won't say that from all the other machines this service has worked for years, but the calls were made wcf self hosting, wcf iis asp.net compatibility hosting -> against the net.tcp service self hosted. When then I published my simple web api calling the same net.tcp service, everything went wrong, and all the connection were aborted without any reason, even the full wcf tracing both sides (service and client) did not helped, just telling the same "connection aborted".

I've already knew that net.tcp comes with the security over transport enabled, using windows authentication to sign and crypt the communication, so well, I just tried to turn off the security and everything start to work properly.

Just give it a try turning off the security in this way both sides (client and service):

<security mode="None"/>

full service binding:

<netTcpBinding>

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

        <security mode="None"/>

    </binding>

</netTcpBinding>

I hope this can help you too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top