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
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.
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 to808:*
? 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 tomydomain.com
after it didn't work on the server:<identity><dns value="mydomain.com" /></identity>
- baseAddress is adjusted to
- 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.
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.