3

I have a duplex WCF channel used in a publish/subscribe pattern. I can not figure out how to cleanly disconnect clients without producing an error in the tracing. The error does not affect the application but shows up in the tracing logs. Since this expected error message is filling up our logs it is hard to figure other issues.

Error that shows up in the server side logs :

"An existing connection was forcibly closed by the remote host" 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)

server code:
        public static void StartHost()
        {
           var startTime = DateTime.Now;
        var duplex = new ServiceHost(typeof(HostChannel));
        try
        {
            duplex.AddServiceEndpoint(typeof(IHostChannel),
                CreateTpcBinding(),
               AppConfiguration.SchedulerHostChannel);
            duplex.Open();

            _duplex = duplex;

        }
        catch (Exception e)
        {
            log.LogError("Error acquiring HostChannel:" + e);
            if (duplex.State == CommunicationState.Faulted)
                duplex.Abort();
            duplex.Close();
            throw;
        }
    }

private static NetTcpBinding CreateTpcBinding()
    {
        return new NetTcpBinding()
        {
            ReliableSession = new OptionalReliableSession() { InactivityTimeout = TimeSpan.FromDays(5) },
            ReceiveTimeout = TimeSpan.FromDays(5),
            ReaderQuotas = new XmlDictionaryReaderQuotas() { MaxStringContentLength = 5242880 }
        };
    }
    /// <summary>
    /// First method the client calls 
    /// </summary>
    public void EstablishConnection()
    {
        var channelBinder = ServiceLocator.Current.GetInstance<RemoteResourceManager>();
        var remoteChannel = OperationContext.Current.GetCallbackChannel<IRemoteChannel>();
        _processHandle = channelBinder.RegisterRemoteChannel(remoteChannel);
    }
    /// <summary>
    /// Last method that is called
    /// </summary>
    public void NotifyComplete()
    {
        _processHandle.Events.OnCompleted(_processHandle.RemoteChannel, new EventArgs());


        log.LogInfo("Try to clean callback channel");
        ((IClientChannel)_processHandle.RemoteChannel).Close();
        ((IClientChannel)OperationContext.Current.GetCallbackChannel<IRemoteChannel>()).Close();
        log.LogInfo("Cleaned callback channel");


    }

Client callback interface :

public interface IRemoteChannel
{
    [OperationContract(IsOneWay = true)]
    void StartTask(TaskDefinition taskDefinition);
    [OperationContract(IsOneWay = true)]
    void RequestCancelTask();
    [OperationContract(IsOneWay = true)]
    void HealthCheck();
} 

Client clean up code after calling NotifyComplete

 if (_proxy is IClientChannel)
            channel = ((IClientChannel)_proxy);

        try
        {
            if (channel != null)
            {
                if (channel.State != CommunicationState.Faulted)
                {
                    channel.Close();
                }
                else
                {
                    channel.Abort();
                }
            }
        }
        catch (CommunicationException e)
        {
            channel.Abort();
        }
        catch (TimeoutException e)
        {
            channel.Abort();
        }
        catch (Exception e)
        {
            channel.Abort();
            throw;
        }
        finally
        {
            _proxy = null;
        }

0 Answers0