Our security department has reported that our WCF services don't implement timeouts or keep-alive approach so I am investigating what configuration we have and created very simple WCF service and noticed that ReceiveTimeout looks to never execute.
I suspect, main problem is that we have implemented our own keep-alive solution, but if someone connects for example from Windows cmd using Telnet, which doesn't execute our ping messages, it should close connection after specified ReceiveTimeout (from my understanding - correct me, if I am wrong - I am not much experienced in WCF)
We are using CoreWcf.NetTcp as application is originally created in .net-framework.
For demo purposes I created this service:
[ServiceContract]
public interface ITestWcfService
{
[OperationContract]
string GetData(int value);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class TestWcfService : ITestWcfService
{
public TestWcfService() //only instantiated by WCF
{
Console.WriteLine("Constructor");
OperationContext.Current.InstanceContext.Faulted += new EventHandler(Channel_Faulted);
OperationContext.Current.InstanceContext.Closed += new EventHandler(Channel_Faulted);
}
private void Channel_Faulted(object sender, EventArgs e)
{
Console.WriteLine("Faulted");
}
public string GetData(int value)
{
Console.WriteLine("GetData");
return $"{value}";
}
}
And have this class
public static class MyTestHostClass
{
public static string ServiceName => "WcfServiceName";
private static WebApplication _app;
public static void Open(int port)
{
var builder = WebApplication.CreateBuilder();
builder.WebHost.UseNetTcp(port);
builder.Services.AddServiceModelServices();
_app = builder.Build();
_app.UseServiceModel(serviceBuilder =>
{
serviceBuilder.AddService<TestWcfService>(options =>
{
});
serviceBuilder.AddServiceEndpoint<TestWcfService, ITestWcfService>(GetTcpBinding(), $"net.tcp://0.0.0.0:{port}/{ServiceName}");
});
_app.StartAsync().Wait();
}
public static void Close()
{
if (_app != null)
{
_app.StopAsync().Wait();
_app.DisposeAsync();
_app = null;
}
}
private static NetTcpBinding GetTcpBinding()
{
Console.WriteLine("Bindings");
var binding = new NetTcpBinding(SecurityMode.Transport)
{
CloseTimeout = TimeSpan.FromSeconds(10),
OpenTimeout = TimeSpan.FromSeconds(10),
ReceiveTimeout = new TimeSpan(0, 0, 0, 10),
SendTimeout = TimeSpan.FromSeconds(10)
};
return binding;
}
}
And finally, my console application starting it:
Console.WriteLine("Hello, World!");
MyTestHostClass.Open(11999);
Console.WriteLine("WCF listening on port 11999");
await Task.Delay(Timeout.Infinite);
I can see message WCF is listening on port 11999
so it looks to start fine
Then I go into cmd in Windows and just run telnet command telnet localhost 11999
- it connects but never disconnects even though it exceeds ReceiveTimeout.
I also checked in WireShark that there is no activity on port 11999 so there shouldn't be reason to keep it alive.
(I also don't see Console log from constructor of WCF Service)
Any ideas what need to be set and why it is not working?
Edit 1: I have tried to host same service in simple WinForms (net4.7.2) application:
public Form1()
{
InitializeComponent();
host = new ServiceHost(typeof(TestWcfService));
var binding = new NetTcpBinding()
{
CloseTimeout = TimeSpan.FromSeconds(10),
OpenTimeout = TimeSpan.FromSeconds(10),
ReceiveTimeout = new TimeSpan(0, 0, 0, 10),
SendTimeout = TimeSpan.FromSeconds(10),
};
host.AddServiceEndpoint(typeof(ITestWcfService), binding, new Uri("net.tcp://localhost:11998/TestWcfService"));
host.Open();
Console.WriteLine("WCF Service listening on 11998");
}
and it timeouts just fine. Does it mean, there is a bug in CoreWCF package or I am missing some part which need to be done in case of CoreWCF?
Edit 2: For a test I created service in both framework4.7.2 and NET6. And then the client in both framework4.7.2 and NET6. The Contract of the service is the same for both services.
Client implementation looks like this (it is actually same in framework and NET6, only difference is that for NET6 I had to install System.ServiceModel.NetTcp nuget.
private ITestWcfService Client;
public Form1()
{
InitializeComponent();
var myBinding = new NetTcpBinding()
{
CloseTimeout = TimeSpan.FromSeconds(5),
OpenTimeout = TimeSpan.FromSeconds(5),
ReceiveTimeout = new TimeSpan(0, 0, 0, 5),
SendTimeout = TimeSpan.FromSeconds(5)
};
var myEndpoint = new EndpointAddress("net.tcp://localhost:11998/TestWcfService");
var myChannelFactory = new ChannelFactory<ITestWcfService>(myBinding, myEndpoint);
try
{
Client = myChannelFactory.CreateChannel();
}
catch
{
}
}
private void button1_Click(object sender, EventArgs e)
{
Client.GetData(5);
}
And here is the summary of behavior: Framework 4.7.2 behaviour:
NET6 behaviour:
But nothing is sent to the client and therefore connection looks still on:
But, if I try to call method from client again, it doesn't reach it. And timeouts in 5 seconds (client timeout)
We can see in the server logs that it didn't reach it at all:
So from my understanding, there is a bug in CoreWCF package.
If someone finds this question and is experiencing same issue, then just update Nuget package to newer version. This is fixed in version 1.5.2 and above.