Jason
Jason

Reputation: 3960

WCF FaultException<SqlException> caught as CommunicationException

I have a WCF service where I am catching an SqlException and then returning it as a FaultException like this

throw new FaultException<SqlException>(...);

And on the client side, I am catching it like this

catch (FaultException<SqlException> e)
{
    // do something with exception
}
catch (FaultException<Exception> e)
{
    // do something with exception
}

I don't believe I have a problem in my web.config on the service side or the app.config on the client side (a winform client) as I am able to catch FaultException<ArgumentException>, FaultException<Exception>, etc. but not FaultException<SqlException>

I have not found anything indicating that I can't pass SqlExceptions down to the client, my operation contract is properly configured with things like [FaultContract(typeof(SqlException))], and [FaultContract(typeof(Exception))]

Anyone seen this or know for a fact that I can't (or maybe need to do something special to) pass faults of type SqlException down to the client? Thank you.

Upvotes: 2

Views: 1507

Answers (2)

Contango
Contango

Reputation: 80272

I ran into this problem because I had a breakpoint in the wrong place. I removed all breakpoints with Debug..Delete all Breakpoints (Ctrl-Alt-F9), and all of the CommunicationException exceptions disappeared and were replaced with the correct messages coming back.

Yes, the timeout is 60 seconds, so this never should have occurred, so it was probably some weird artifact of Visual Studio 2012.

Upvotes: 0

Christian Hayter
Christian Hayter

Reputation: 31071

throw new FaultException<Exception> is not really how the WCF fault system is intended to be used. The type you specify is serialized across the wire in the <Detail> element of a SOAP fault. Normally, this type is a WCF data contract class that you write, e.g.

[DataContract]
public class MyFault {
    [DataMember]
    public string Message {get; set;}
}

throw new FaultException<Exception> happens to work because Exception is [Serializable], and the DataContractSerializer is capable of handling [Serializable] types as well as [DataContract] types.

However, there are serious limitations to this approach. The DataContractSerializer does not handle [Serializable] types very well. Only fields of primitive types (string, int, etc) will be transmitted correctly. That is just about OK for a very simple exception type, but for a complex type like SqlException, it's not good enough.

My suggested solution is: create your own dedicated data contract to pass back the data from SqlException that you require, then throw that instead. In fact, do this for all exception types, it's more secure and better practice. I use Enterprise Library Exception Shielding to handle this automatically. All that gets passed back to the client is a single GUID value identifying the error data in the server log.

Alternatively, if you are determined to go down the exception route, see this detailed article.

Upvotes: 4

Related Questions