Setting up WCF TCP service in a web application
Asked Answered
R

7

29

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.

Retrospective answered 18/5, 2013 at 19:53 Comment(2)
Have you enabled the WCF non-HTTP activation components? (details here msdn.microsoft.com/en-us/library/ms731053.aspx). Also have you added tcp to allowed protocols for your web site? (Mange Web Site -> Advance Settings -> Enabled Protocol). Have you tried generating proxy based on the metadata exposed over HTTP? (test.mydomain.com/SignalR/ServerHubService.svc)Sizemore
I had forgotten to enabled Non-HTTP Activaition (I had done it on my test server only). Unfortunately I get the same error after enabling this. I had already remembered net.tcp under Advanced settings but have now added it to the question details. I get an interesting error if I try to generate the proxy based on http - I will update the question with this.Retrospective
O
7

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

Otten answered 22/5, 2013 at 8:19 Comment(10)
Ahh, I actually have httpGetEnabled=false in the "ServiceHubBehavior". I'll try editing this and see if it makes a difference. Thanks.Retrospective
It worked. It's now possible to add it from WCF Test Client and create a service reference from my actual client ... the actual call still doesn't work, but I'll update the question with that...Retrospective
Try creating Service Proxy with the TCP mex address (net.tcp://computername/SignalR/ServerHubService.svc) instead of http.. If the servie reference is added successfully then the method invoke also should work. From the above error it is clear that the service is not listening at the port 808.Check the port number of the TCP protocol for the site you have created in IIS.Otten
I tried using the net.tcp address to create the service reference, with and without :808 in the url. But you may be on to something, because I ran netstat -an |find /i "listening" and found that nothing is listening on port 808Retrospective
The above comment is now outdated. I had previously enabled Net.Tcp Listener Adapter, but it had stopped in the mean time, this was the reason why nothing was listening on port 808. Now I can see it's listening on port 808.Retrospective
If it is working correctly in local then your server configuration shouldn't have any issues. make sure your client points to the right url(net.tcp://mydomain.com:808/SignalR/ServerHubService.svc) and not the localhost one.The port number may or may not be included since 808 is the default port for net.tcp.Otten
Thanks for following up. I did check the client configuration on the remote server. I have added the configuration details to the bottom of the question.Retrospective
Can you provide the complete exception detail.And try to ping on that host name and port or else try with http from the same remote server and see wether it works.Otten
I cannot ping because it's disabled, but I can telnet which should indicate that the port is open. I get an empty console after executing telnet mydomain.com 808Retrospective
Check with the IIS log for the particular site to analyse further. And the complete error message would be helpfulOtten
H
2

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>
Hithermost answered 22/5, 2013 at 21:14 Comment(1)
This doesn't result in any visible difference. After doing this, when I run WCF Test Client, the result is the same: It finds the service, but it cannot be invoked, and the error message reveals it's trying to call computernameRetrospective
S
0

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.

Spiffy answered 18/5, 2013 at 19:53 Comment(0)
F
0

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

Ferretti answered 18/5, 2013 at 19:53 Comment(5)
Yes I do have this running. I will add that detail to the question. Thanks.Retrospective
Also you are using the same security setting on both sides I assume (the example in your question is not the actual real code is it).Ferretti
I've just found an interesting article saying if you set your net.tcp iis binding and it still doesn't work holsson.wordpress.com/2009/09/24/… then set it manually :) also an interesting comment: "if it’s 808:* your service will be accessible under net.tcp://localhost/MyServices/Service1.svc" eg on the default address without port qualifier.Ferretti
Thanks. The example in my question is very close to real code. I have no firewall on the server or in the environment, which must be why I can telnet to port 808 remotely. It's very interesting about 808 being the 'default' port for net.tcp, I will definitely try without the 808 in the endpointRetrospective
Regarding security, it is my intention to run without any kind of security, just to get it up and running.Retrospective
E
0

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.

Epicurus answered 18/5, 2013 at 19:53 Comment(1)
It actually works on my local machine. The current problem is with deployment on the server.Retrospective
B
0

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?

Bivins answered 18/5, 2013 at 19:53 Comment(4)
Note, I am not hosting the WCF in a service, but in a web application. The application pool is actually running as the local Administrator on the server. I've tried setting the baseAddress to the ip address as you suggested, but no luck.Retrospective
Regarding Kerberos and Windows Authentication: I'm surprised that this should be necessary as I didn't enable of those features. But I will try to work with SPN to see if it helps.Retrospective
Reading again into your question, I think my suggestion might not be relevant. Feel free to ignore. I will leave it anyway for completeness of the discussion.Bivins
Thankyou for that follow-up, Ashraf ... do you have any other suggestions?Retrospective
N
0

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

Nonpartisan answered 24/5, 2013 at 22:14 Comment(4)
It's not possible in my scenario, it has to be a web application.Retrospective
Or is it also possible to let the web application self host the WCF service?Retrospective
Have you looked at this blog? blogs.msdn.com/b/prathul/archive/2011/11/28/…Nonpartisan
I went through it. I did everything mentioned in the blog.Retrospective

© 2022 - 2024 — McMap. All rights reserved.