パブリッシュ/サブスクライブ パターンで使用される二重 WCF チャネルがあります。トレースでエラーを発生させずにクライアントをきれいに切断する方法がわかりません。このエラーはアプリケーションには影響しませんが、トレース ログに表示されます。この予想されるエラー メッセージでログがいっぱいになるため、他の問題を特定するのは困難です。
サーバー側のログに表示されるエラー:
「既存の接続がリモート ホストによって強制的に閉じられました」 socketError、Int32 bytesTransferred、SocketFlags フラグ) 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;
}