诊断WCF通道故障,其中服务在方法返回后关闭套接字

时间:2013-04-02 21:44:12

标签: c# wcf

我在WCF客户端上收到一个异常情况,在这种情况下,合同方法在服务上完成 - 即在服务返回之后和客户端代理返回之前发生异常。

我已经确认,引发问题与返回类型是给定类型的数组这一事实有关,而数组包含派生类型的实例。对于非WCF用法,在返回此数组时没有异常(如代码所示),并且当从客户端调用该方法时,它将在服务端返回。

现在,中抛出的异常我可以捕获的方法,或者如果我没有抓住那么接收客户端,但是这种问题显然是被悄悄地吞噬了。可以从客户端异常收集的唯一信息是连接关闭后的套接字错误!

如果我们挂钩Closing / Faulted事件,我们会看到一个故障&在服务端关闭,然后在异常之前在客户端关闭故障。

按照下面的最小情况,请注意我正在尝试多种方式来获取其他信息。注意:我省略了实际的ServiceContract,因为它在实现中足够清楚(只有一种方法)。

public class BaseItem {}
public class DerivedItem : BaseItem {}

// Service implementation plus fault & error handling
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, IncludeExceptionDetailInFaults = true, UseSynchronizationContext = false)]
public class BasicService : IMyService, IErrorHandler {

    BaseItem[] IMyService.GetItems(bool useDerived) {
        return new BaseItem[] { useDerived ? new DerivedItem() : new BaseItem() };
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault) {}

    public bool HandleError(Exception error) { return false; }
}


public class ClientLauncher {
    public static void LaunchClient() {
        IMyService service = new BasicService();

        BaseItem[] items = service.GetItems(false); // Works fine
        items = service.GetItems(true); // Works fine

        ServiceHost host = new ServiceHost(service); // Singleton instance
        host.AddServiceEndpoint(typeof(IMyService), new NetTcpBinding(),
            "net.tcp://localhost:8000");
        host.Open();

        // Adding service as the implementation of IErrorHandler
        ((ChannelDispatcher)host.ChannelDispatchers[0]).ErrorHandlers.Add((IErrorHandler)service);

        var myFactory = new ChannelFactory<IMyService>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8000"));
        IMyService client = myFactory.CreateChannel();

        try {
            items = client.GetItems(false); // Works fine
            items = client.GetItems(true); // Results in channel faulted, then exception
        }
        catch (Exception ex) {
            string str = ex.ToString();
        }
    }
}

GetItems的直接调用工作正常,并且客户端调用GetItems有效但仅当数组没有派生类型的实例时才有效。数组是必要的 - 如果方法返回单DerivedItem,则返回BaseItem没问题。

但同样真正的问题是更一般 - 无论特定的挑衅问题,我们怎么能在1时找到任何关于它的事情。例外似乎只表明套接字已关闭的事实服务和2.虽然添加了IErrorHandler,但是没有被调用?我真的很想使用WCF,但如果这是所有例外情况,我的信心会非常震撼:

************** Exception Text **************
System.ServiceModel.CommunicationException: The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.9090000'. ---> System.IO.IOException: The read operation failed, see inner exception. ---> System.ServiceModel.CommunicationException: The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:00:59.9090000'. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
   at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
   at System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing)
   --- End of inner exception stack trace ---
   at System.ServiceModel.Channels.SocketConnection.ReadCore(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout, Boolean closing)
   at System.ServiceModel.Channels.SocketConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
   at System.ServiceModel.Channels.DelegatingConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
   at System.ServiceModel.Channels.ConnectionStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.Net.FixedSizeReader.ReadPacket(Byte[] buffer, Int32 offset, Int32 count)
   at System.Net.Security.NegotiateStream.StartFrameHeader(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.NegotiateStream.ProcessRead(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
   --- End of inner exception stack trace ---
   at System.Net.Security.NegotiateStream.ProcessRead(Byte[] buffer, Int32 offset, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.NegotiateStream.Read(Byte[] buffer, Int32 offset, Int32 count)
   at System.ServiceModel.Channels.StreamConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
   --- End of inner exception stack trace ---

Server stack trace: 
   at System.ServiceModel.Channels.StreamConnection.Read(Byte[] buffer, Int32 offset, Int32 size, TimeSpan timeout)
   at System.ServiceModel.Channels.SessionConnectionReader.Receive(TimeSpan timeout)
   at System.ServiceModel.Channels.SynchronizedMessageSource.Receive(TimeSpan timeout)
   at System.ServiceModel.Channels.FramingDuplexSessionChannel.Receive(TimeSpan timeout)
   at System.ServiceModel.Channels.FramingDuplexSessionChannel.TryReceive(TimeSpan timeout, Message& message)
   at System.ServiceModel.Dispatcher.DuplexChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at KapLogic.Aegis.Drivers.P2000.Common.WCF.IMyService.GetItems(Boolean useDerived)
   at KapLogic.Aegis.Drivers.P2000.Common.WCF.ClientLauncher.LaunchClient()

1 个答案:

答案 0 :(得分:1)

使用KnownType属性修饰BaseItem并将DerivedItem指定为属性中的已知类型应该可以解决问题。

例如 - 代码:

[DataContract]
[KnownType(typeof(DerivedItem))]
public class BaseItem { }

摘自MSDN:“KnownTypeAttribute类允许您事先指定在反序列化期间应包括的类型。有关工作示例,请参阅已知类型示例。”

可在以下网址找到更多信息:http://msdn.microsoft.com/en-us/library/ms730167.aspx