コントラクト メソッドがサービスで完了するという非常に特殊なケースで、WCF クライアントで例外を受け取ります。つまり、例外は、サービスへのリターンの後、クライアント プロキシへのリターンの前に発生します。
挑発的な問題は、戻り値の型が特定の型の配列であり、配列には派生型のインスタンスが含まれているという事実に関連していることを確認しました。非 WCF の使用では、(コードが示すように) この配列を返す際に例外はまったくなく、メソッドがクライアントから呼び出されると、サービス側で返されます。
現在、メソッド内からスローされた例外はキャッチできますが、キャッチに失敗した場合はクライアント側で受け取ることができますが、この種の問題は明らかに静かに飲み込まれ、クライアント側の例外から収集できる唯一の情報はソケットエラーです接続が閉じられた後!
Closing/Faulted イベントをフックすると、例外の前にサービス側で Fault & Close が表示され、次にクライアント側で Fault が表示されます。
以下の最小限のケースに従ってください。追加情報を取得するために複数の方法を試していることに注意してください。注:実際ServiceContract
の実装から十分に明らかであるため(メソッドは1つだけ)省略しました。
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
メソッドが single を返した場合、 a を返すことに問題はありません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()