问题
One of the things I never understood about WCF is why no Exception message details are propagated back to the calling client when the server encounters an unhandled exception.
For example, if I have the following server code
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class Server : IServer
{
public DTO GetDTO()
{
DTO dto = new DTO();
dto.dto = dto;
return dto;
}
}
public class DTO
{
public DTO dto;
}
[ServiceContract]
public interface IServer
{
[OperationContract]
DTO GetDTO();
}
I deliberately introduced an ObjectGraph to cause a serialization exception when the DTO object is returned.
If I have a client that calls this Server's GetDTO()
method, I will get the following 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:58.9350000'.
Which is absolutely useless. It has no inner exception and not even the real exception message.
If you then use Microsoft Service TraceViewer, you will see the exception but you must turn on the Diagnostics tracing for this.
The exception message that should be sent back is
There was an error while trying to serialize parameter http://tempuri.org/:GetDTOResult. The InnerException message was 'Object graph for type 'TestWCFLib.DTO' contains cycles and cannot be serialized if reference tracking is disabled.'. Please see InnerException for more details.
So can anybody tell me how get the right exception message show up on the client side? Obviously, setting IncludeExceptionDetailInFaults
to true doesn't make a difference.
回答1:
I think that it is by design that the server errors are not propogated to client. This is in general a practice to not expose server internals to clients as the main purpose of Client Server architecture is independence of server.
You can still achieve this by using Fault Exception
Decorate your service declaration with a fault contract
[ServiceContract]
public interface IServer
{
[OperationContract]
[FaultContract(typeof(MyApplicationFault))]
DTO GetDTO();
}
Then catch errors in servcie implementation and throw a fault exception.
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class Server : IServer
{
public DTO GetDTO()
{
try
{
DTO dto = new DTO();
dto.dto = dto;
return dto;
}
catch (Exception ex)
{
MyApplicationFault fault = new MyApplicationFault(...);
throw new FaultException<MyApplicationFault>(fault);
}
}
}
And catch the exception in client
IServer proxy = ...; //Get proxy from somewhere
try
{
proxy.GetDTO();
}
catch (TimeoutException) { ... }
catch (FaultException<MyApplicationFault> myFault) {
MyApplicationFault detail = myFault.Detail;
//Do something with the actual fault
}
catch (FaultException otherFault) { ... }
catch (CommunicationException) { ... }
Hope this helps. For a nice tutorial please see Code Project Tutorial on Fault Exception
来源:https://stackoverflow.com/questions/7404478/wcf-communicationexception-with-no-exception-message-details