进行客户端 WCF 调用时如何防止“System.AccessViolationException”?

Cli*_*lif 5 .net c# wcf

我正在运行一个 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)

这个问题非常难以重现,并且似乎没有显示任何其他模式,任何帮助将不胜感激。