views:

341

answers:

1

I have this simple test project just to test the IncludeExceptionDetailInFaults behavior.

    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            throw new InvalidCastException("test");
            return string.Format("You entered: {0}", value);
        }
    }

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetData(int value);
    }

In the app.config of the service i have it set to true

 <serviceDebug includeExceptionDetailInFaults="True" />

On the client side:

            try
            {
                using (var proxy = new ServiceReference1.Service1Client())
                    Console.WriteLine(proxy.GetData(5));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

This is what I thought the behavior was: Setting to includeExceptionDetailInFaults=true would propagate the exception detail to the client. But I'm always getting the CommunicationObjectFaultException.

I did try having the FaultContract(typeof(InvalidCastException)) on the contract but same behavior, only getting the CommunicationObjectFaultException.

The only way to make it work was to throw new FaultException(new InvalidCastException("test"));

But I thought with IncludeExceptionDetailInFaults=true the above was done automatically.

Am I missing something?

+1  A: 

It's because you've put the service client inside a using block.

WCF clients are the one place in .NET where you shouldn't use using, because it will mask the "real" exception.

Technical explanation: Dispose calls Close, which will always throw a CommunicationObjectFaultedException if the channel is already faulted (i.e. as a result of a previous exception), which subsequently puts that exception at the top of the stack. When cleaning up an ICommunicationObject, in order to avoid masking the exception, you have to first check the State to see if it is faulted, and if so call Abort instead of Close.

Aaronaught
ah thanks! what does Close do to cause a communicationobjectfaultexception when the channel is faulted?
pdiddy
@pdiddy: `CommunicationObject.Close` is literally programmed to throw an exception if the channel is faulted. It's not accidental.
Aaronaught
Couldn't it check for the state and abort when the channel is faulted? Just wondering why it's implemented that way.
pdiddy
@pdiddy: It does check the state, and it does call `Abort`... and then it throws an exception. I'm sure that it *could* do many other things, but that's the way the WCF team chose to implement it, to the detriment of many. It's even documented on MSDN now: http://msdn.microsoft.com/en-us/library/ms733912.aspx
Aaronaught