我在发布/订阅模式中使用了双工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;
}