My WCF Service in C# looks like this.
[ServiceContract]
public class MySecretService
{
[OperationContract]
[FaultContract(typeof(ErrorMessage))]
public MyDTO ReturnMyDTOMethod(int id, out string errorMessage)
{
try
{
//Do stuff...
//Do some more stuff... pseudocode
if (biz rule 1 && etc)
{
return MyDTO;
}
else if (biz rule 2 && etc)
{
return null;
}
else
{
throw new FaultException<ErrorMessage>(blah etc..)
}
}
catch (Exception e)
{
throw new FaultException<ErrorMessage>(blah etc...);
}
}//end-method
}//end-class
The DTO to be returned from the method looks like this:
[DataContract]
public class MyDTO
{
[DataMember]
public XElement XmlRep
{
get
{
//do something within setter, etc...
//error occurs prior to returnin from setter, where to i catch it?
return _xmlRep
}
set
{
_xmlRep = value;
}
}
}
The typical examples that i found shows throwing a FaultException from within the method; But in my case, my method does not error; The error occurs at the time when the object is being returned to the client/consumer; i.e when the DataMember/Property XmlRep is being serialized;
So i cannot place the throw FaultException within my method; But i still want to avoid getting "The underlying connection was closed: The connection was closed unexpectedly." and throw the proper error that occurs within the getter.
I have not tried putting try/catch inside the getter of MyDTO, NOR DO I WANT TO BECAUSE i want my DTO to be as simple as possible, and know nothing about FaultExceptions and WCF stuff. Any other ideas ?
EDIT: Just to make it clearer, i know the error is occurring in the Getter of MyDto DataContract; But where else would i throw the FaultException, given that inside the Getter seems to me like a dodgy place to throw it?
EDIT#2: I implemented a catch-all error handler on the service side as suggested by Tim below (using IErrorHandler); this does not work in my specific case. I think this is because the Error does not occur within the OperationContract ReturnMyDTOMethod(), but instead within the MyDto when is being serialized; In other words, it appears the horse has bolted (method returns successfully), and it is to late for the IErrorHandler to be of any use - Specifically ProvideFault() does not fire but HandleError() does fire. Consequently i still get a channel broken message, which requires me to go back to the drawing board - i.e. ensure MyDto does not do anything fancy such as generate an error!
Two options I see:
It sounds like something in your DataContract isn't able to be serialized. I would take a look there and determine what that is, why it isn't being serialized, and if there is some other way you can handle the issue within the setter. You may be able to do that without a try-catch block, depending on what it is. Without seeing the code or knowing what the actual error is, it's hard to give anything more specific.
Implement IErrorHandler Interface in your service. This will catch any unhandled exceptions and you to handle them as your service needs (for example, serializing an error message via FaultException). There are plenty of examples on the web of how to do that - simply google IErrorHandler and WCF.
My personal preference would be to try approach #1 - there's probably a specific reason (or group of reasons) your DTO isn't serializing, and I feel it's better to handle those issues within the code rather than relying on some sort of global error handler (which is what #2 would be).
Also, depending on the logic in your setter, you may have already made your DTO complex. I generally try to avoid any logic in my setter unless it's something simple like a null check.
Added After 2nd Edit in Question
The documentation for IErrorHandler states:
"Exceptions can occur after all ProvideFault implementations are called and a response message is handed to the channel. If a channel exception occurs (for example, difficulty serializing the message) IErrorHandler objects are not notified. In this case, you should make sure that your development environment catches and displays such exceptions to you or makes use of tracing to discover the problem." (Emphasis mine)
Do you know what is causing the serialization to fail? If you do, I would think you could address it in the code itself. Have you enabled tracing? It seems to me that you need to determine why your DTO can't serialize.