我正在运行一个 Windows 服务,该服务正在对其他地方运行的多个其他 WCF 服务进行多次调用。有时,我们的客户在调用端点时会遇到无法捕获的异常,从而导致我们的服务瘫痪。端点的服务器端正在运行一个实例,除了它进行的数据库调用之外,该实例是完全无状态的。
例外是“System.AccessViolationException”,我知道它属于损坏状态异常的类别,正如我在此处阅读的那样。
我知道 [HandleProcessCorruptedStateExceptions] 属性,以及所有反对使用它来处理不由异常捕获器维护的代码的警告。
调用堆栈的顶部深入研究了 WCF 包装的本机 Windows 库:
System.AccessViolationException Stack:
at System.Net.UnsafeNclNativeMethods+OSSOCK.recv(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags)
at System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError ByRef)
at System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[], Int32, Int32)
at System.Net.PooledStream.Read(Byte[], Int32, Int32)
at System.Net.Connection.SyncRead(System.Net.HttpWebRequest, Boolean, Boolean)
at System.Net.Connection.PollAndRead(System.Net.HttpWebRequest, Boolean)
at System.Net.ConnectStream.WriteHeaders(Boolean)
at System.Net.HttpWebRequest.EndSubmitRequest()
at System.Net.HttpWebRequest.SetRequestSubmitDone(System.Net.ConnectStream)
at System.Net.Connection.CompleteStartRequest(Boolean, System.Net.HttpWebRequest, System.Net.TriState)
at System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest, Boolean)
at System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest, System.String)
at System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint)
at System.Net.HttpWebRequest.GetRequestStream(System.Net.TransportContext ByRef)
at System.Net.HttpWebRequest.GetRequestStream()
at System.ServiceModel.Channels.HttpOutput+WebRequestHttpOutput.GetOutputStream()
at System.ServiceModel.Channels.HttpOutput.Send(System.TimeSpan)
at System.ServiceModel.Channels.HttpChannelFactory`1+HttpRequestChannel+HttpChannelRequest[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].SendRequest(System.ServiceModel.Channels.Message, System.TimeSpan)
at System.ServiceModel.Channels.RequestChannel.Request(System.ServiceModel.Channels.Message, System.TimeSpan)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(System.ServiceModel.Channels.Message, System.TimeSpan)
at System.ServiceModel.Channels.ServiceChannel.Call(System.String, Boolean, System.ServiceModel.Dispatcher.ProxyOperationRuntime, System.Object[], System.Object[], System.TimeSpan)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage, System.ServiceModel.Dispatcher.ProxyOperationRuntime)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32)
at WCFCommunicator.IComEndpoint.TestEndpoint()
at WCFCommunicator.SendingLayer+<>c.<VerifyCurrentEndpoints>b__38_0(WCFCommunicator.IComEndpoint)
at WCFCommunicator.HttpWrapper.Client`2[[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.__Canon, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].UseCom[[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]](System.Func`2<System.__Canon,Boolean>, ErrorType ByRef, System.String)
at WCFCommunicator.SendingLayer.VerifyCurrentEndpoints()
at WCFCommunicator.LocalSubscriptionAnalyzer.ValidateEndpoints_Elapsed(System.Object, System.Timers.ElapsedEventArgs)
at System.Timers.Timer.MyTimerCallback(System.Object)
at System.Threading.TimerQueueTimer.CallCallbackInContext(System.Object)
at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading.TimerQueueTimer.CallCallback() at System.Threading.TimerQueueTimer.Fire() at System.Threading.TimerQueue.FireNextTimers()
at System.Threading.TimerQueue.AppDomainTimerCallback()
Run Code Online (Sandbox Code Playgroud)
客户端代码始终作为 lambda 传入并在 try/catch/finally 中执行,如下所示:
public TReturn UseCom<TReturn>(Func<Com, TReturn> code)
{
Com channel = cFactory.CreateChannel();
bool error = true;
try
{
TReturn result = code(channel);
((IClientChannel)channel).Close();
error = false;
return result;
}
catch (EndpointNotFoundException e)
{
//log and handle
return default(TReturn);
}
catch (FaultException e)
{
//log and handle
return default(TReturn);
}
catch (CommunicationException e)
{
//log and handle
return default(TReturn);
}
catch (Exception e)
{
//log and handle
return default(TReturn);
}
finally
{
if (error)
{
((IClientChannel)channel).Abort();
}
}
}
Run Code Online (Sandbox Code Playgroud)
其用法如下:
var result = clientInstance.UseCom(endpoint => endpoint.TestEndpoint());
Run Code Online (Sandbox Code Playgroud)
这个问题非常难以重现,并且似乎没有显示任何其他模式,任何帮助将不胜感激。