Please don't close as duplicate until you read the question to the end; I already googled for hours without success.
EDIT: Now I'm convinced it's related to the way WCF caches opened TCP connections (connection pooling). Please take a look at edit #5 at the end of he question.
I basically have a WCF service that uses a netTcpBinding
configuration. Even if I close the client proxy gracefully (see code below), server always logs "System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host
".
I've narrowed down the issue to the most basic WCF example I could write. I'm getting the exception in the logs produced by WCF tracing every-time I close the client application. I'm not getting any exception in my own code though, which means it works as expected and I can't debug anything to see what's going wrong for WCF to add an error in my logs.
Service interface/implementation:
[ServiceContract]
public interface IService1
{
[OperationContract]
string DoWork();
}
...
public class Service1 : IService1
{
public string DoWork()
{
return "12";
}
}
Server-side configuration:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="WebApplication1.Service1">
<endpoint address="" binding="netTcpBinding" bindingConfiguration="netTcpEndpointBinding" contract="WebApplication1.IService1" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="netTcpEndpointBinding">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>
Client-side configuration:
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="NetTcpBinding_IService1">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost/WebApplication1/Service1.svc"
binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IService1"
contract="ServiceReference1.IService1" name="NetTcpBinding_IService1" />
</client>
</system.serviceModel>
</configuration>
Client-side code that consumes the service (VS2012 generated the client proxy for me using "Add service reference"):
private async Task<string> TestTask()
{
Service1Client proxy = null;
try
{
Console.WriteLine("Calling service");
proxy = new Service1Client();
return await proxy.DoWorkAsync();
}
finally
{
if (proxy.State != System.ServiceModel.CommunicationState.Faulted)
{
Console.WriteLine("Closing client");
proxy.Close();
}
else
{
Console.WriteLine("Aborting client");
proxy.Abort();
}
}
}
Everything works fine:
Calling service
Closing client
12
But as soon as the application terminates, the server logs an exception. I understand I shouldn't be worried about this exception because it works as expected (exception only appears in logs) and could happen anyway in case the client is terminated abruptly before calling .Close()
/.Abort()
.
But still, is this a normal behavior? I mean, if I correctly closes my client proxy, I expect the server to not log an exception (that is polluting my logs). I also assume some TCP connection is still established between the client and the server (unknown state) after closing the client proxy, because the server only logs the exception after the whole client application terminates. If such a connection is still opened, can't this introduce unexpected behavior (such as max number of connected clients)? Is this really expected?
I found different threads about the issue:
wcf "An existing connection was forcibly closed by the remote host" after closing client
The conclusion would be "don't care about it".
Could someone confirm that with some references and explain why this exception is thrown anyway?
EDIT:
Log trace of the exception:
<Exception>
<ExceptionType>System.Net.Sockets.SocketException, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>An existing connection was forcibly closed by the remote host</Message>
<StackTrace>
à System.ServiceModel.Channels.SocketConnection.HandleReceiveAsyncCompleted()
à System.ServiceModel.Channels.SocketConnection.OnReceiveAsync(Object sender, SocketAsyncEventArgs eventArgs)
à System.Net.Sockets.SocketAsyncEventArgs.FinishOperationAsyncFailure(SocketError socketError, Int32 bytesTransferred, SocketFlags flags)
à System.Net.Sockets.SocketAsyncEventArgs.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
à System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)
</StackTrace>
<ExceptionString>System.Net.Sockets.SocketException (0x80004005): An existing connection was forcibly closed by the remote host</ExceptionString>
<NativeErrorCode>2746</NativeErrorCode>
</Exception>
Thanks a lot
EDIT 2: I have the same problem when hosting the service in IIS or when it's self-hosted in a Windows service
EDIT 3: here's a full example to reproduce the issue: http://speedy.sh/ENB59/wcf-test.zip
EDIT 4:
I tried to monitor what is actually happening under the hood with the TCP connection WCF establishes for me.
After closing the client proxy, I still see an opened TCP connection to my server:
I assume this is related to the TCP connection to be cached for a future re-use (i.e. connection pooling), because opening a new connection to the server (after the first client proxy has been closed) doesn't create a new TCP connection. If I call Console.WriteLine(new Test().TestTask().Result);
twice in my application, I still only see one opened TCP connection.
I also noted this connection dies because of a timeout if I wait too long after closing the client channel.
EDIT 5: OK, I found documentation on MSDN about that connection pooling:
The NetTcpBinding uses TCP connection pooling based on the service’s host DNS name and the port number the service is listening on. This works well when a client makes calls to different services on different ports, or services are hosted in a single process and share a port. If a single client calls multiple services sharing a port that are hosted in different processes, or are WAS/IIS hosted, the client side pooling may lead to problems where a connection to Service A is reused for Service B, resulting in an exception being thrown, the connection aborted, and a new channel created. To avoid this problem, use a CustomBinding and specify a different ConnectionPoolSettings.GroupName for each service the client communicates with.
So now my question would be: if that's a normal behavior, what could I do to prevent my log to be polluted with all those exceptions?
To resolve this error, simply close the Channel Factory as well.
private async Task<string> TestTask()
{
Service1Client proxy = null;
try
{
Console.WriteLine("Calling service");
proxy = new Service1Client();
return await proxy.DoWorkAsync();
}
finally
{
if (proxy.State != System.ServiceModel.CommunicationState.Faulted)
{
Console.WriteLine("Closing client");
proxy.ChannelFactory.Close();
proxy.Close();
}
else
{
Console.WriteLine("Aborting client");
proxy.Abort();
}
}
}
Edit Ok. I was able to reproduce the problem using your code. The good news is that I also stumbled upon a way to not reproduce it. I do not think that you have any problem in your code. I think that the error is being logged because you are running it in the debugger in VS; and when the debugger shutting down the service is causing the error to get logged.
Follow these steps and see if you no longer get the error (this works perfectly for me every time):
- Right-click on the service project and choose Debug > Start New Instance
- Right-click on the console application and choose Debug > Start New Instance
- Run the console to completion.
- Check your log file.
- Stop the service using the WCF Test Client window and not the debugger stop button.
- Check your log file.
Here's a link to a shock wave video of me doing the above steps: swf file
Orginal The code you posted works just fine on my system. I'm receiving no errors in any logs. As an aside, I would get rid of the catch block completely, as it is doing nothing but rethrowing the exception. Then I'd write the finally block like this below. I think it makes the code cleaner and conveys the idea to the reader that you are not doing anything if an exception is thrown.
Service1Client proxy = null;
try
{
Console.WriteLine("Calling service");
proxy = new Service1Client();
return await proxy.DoWorkAsync();
}
finally
{
if (proxy != null)
{
if (proxy.State == CommunicationState.Faulted)
{
Console.WriteLine("Aborting client");
proxy.Abort();
}
else
{
Console.WriteLine("Closing client");
proxy.Close();
}
}
}
I suspect your return command within the try block is causing execution to skip the finally block causing your connection to remain open until client shutdown causes the exception. Is this possible? Have you made sure that your finally block is executed?
来源:https://stackoverflow.com/questions/20749484/how-to-properly-close-a-client-proxy-an-existing-connection-was-forcibly-closed