我有一个用于发布/订阅模式的双工 WCF 通道。我无法弄清楚如何在不产生跟踪错误的情况下干净地断开客户端。该错误不会影响应用程序,但会显示在跟踪日志中。由于这个预期的错误消息正在填满我们的日志,因此很难找出其他问题。
服务器端日志中显示的错误:
“现有连接被远程主机强行关闭” 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");
}
客户端回调接口:
public interface IRemoteChannel
{
[OperationContract(IsOneWay = true)]
void StartTask(TaskDefinition taskDefinition);
[OperationContract(IsOneWay = true)]
void RequestCancelTask();
[OperationContract(IsOneWay = true)]
void HealthCheck();
}
调用 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;
}