0

I'm banging my head against the wall on this issue, and have checked all the other similar questions on SO to no avail. I've got a simple FaultException that I'm throwing on a WCF server and catching on the client.

Here's the contract:

[ServiceContract]
public interface MyContract
{
    [OperationContract, FaultContract(typeof(TDetail))]
    void ThrowException();
}

[DataContract]
public class TDetail 
{
    public TDetail(string test) {
        Test = test;
    }
    [DataMember]
    public string Test { get; set; }
}

The server code throwing the exception:

throw new FaultException<TDetail>(new TDetail("Test"), "My test fault.");

The XML the client receives (courtesy of Fiddler):

I'm a bit suspicious of this, since my class is named "TDetail", not "Sender".

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <s:Fault>
            <faultcode>s:Client</faultcode>
            <faultstring xml:lang="en-US">My test fault.</faultstring>
            <detail>
                <Sender xmlns:a="http://schemas.datacontract.org/2004/07/Sample.Namespace" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                    <a:Test>MyTest</a:Test>
                </Sender>
            </detail>
        </s:Fault>
    </s:Body>
</s:Envelope>

The client code getting the exception:

catch (FaultException<TDetail> ex)
{
    // I expect this
}
catch (FaultException ex)
{
    // But get this D:
}

And the exception the client receives:

System.ServiceModel.FaultException was caught
  HResult=-2146233087
  Message=My test fault.
  Source=mscorlib
  StackTrace:
    Server stack trace: 
       at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
       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 Sample.Namespace.ThrowException()
  InnerException: 

For the life of me I cannot figure out why TDetail is apparently being thrown out by the client. I'm certain that both the client and the server are referencing the same class (I literally copy-pasted the DLL into the right folders), and my implementation is hardly complex. This was even working fine last year, and I can't find any substantial code changes made since then.

Any help? :(

On why my question isn't the same as the potential duplicate: The duplicate's setup is a good deal more complex. Most obviously, they're actually implementing a custom ErrorHandler and creating their own fault (which is where the issue was), which I'm not. Their answer doesn't apply to my situation.

Final solution: I ended up having to specify the Name/Namespace in both the FaultContract and when I was throwing the FaultException.

[ServiceContract(Namespace = "MyNamespace")]
public interface MyContract
{
    [OperationContract]
    [FaultContract(typeof(TDetail), Name = "TDetail"]
    void ThrowException();
}

throw new FaultException<TDetail>(new TDetail("Test"), 
    "My test fault.", 
    new FaultCode("TDetail", "MyNamespace));

I'm not 100% yet on why it has to be that way, but at least it works!

Crystal
  • 153
  • 1
  • 10
  • Possible duplicate of [client will not catch generic FaultException< T >, only FaultException](http://stackoverflow.com/questions/6588320/client-will-not-catch-generic-faultexception-t-only-faultexception) – Wicher Visser May 20 '16 at 15:40
  • Edit on why it isn't. – Crystal May 20 '16 at 15:52
  • Fair point. Could it be that Detail cannot be deserialized by the client? You may have to make it a KnownType on the WCF interface. – Wicher Visser May 20 '16 at 16:00

1 Answers1

0

I tried it out myself and found the same problem. Then I tried adding Names and Namespaces and then it worked.

[ServiceContract(Name = "MyContract", Namespace = "MyNameSpace")]
public interface MyContract
{
    [OperationContract, FaultContract(typeof(TDetail))]
    void ThrowException();
}

[DataContract(Name = "TDetail", Namespace = "MyNameSpace")]
public class TDetail
{
    public TDetail(string test)
    {
        Test = test;
    }
    [DataMember]
    public string Test { get; set; }
}

I think what happened is that when you host the same code on different assemblies, it takes on the namespace of that assembly and thus doesn't match up when the client connects to the service, hence the need to specify the Namespace at least on the data contract.

Always remember to properly specify your contracts kids ;-)

Dandré
  • 2,053
  • 3
  • 18
  • 38
  • You are a golden god. That wasn't _exactly_ it, but it was very close and eventually led to solving the issue. Thank you! – Crystal May 20 '16 at 18:13
  • I wouldn't go that far but you are welcome. What exactly was the issue? – Dandré May 20 '16 at 20:43
  • Maybe a minor golden god? It seemed to be a namespace mismatch, but I also had to add the FaultCode when throwing the exception. I added more detail to the post. – Crystal May 27 '16 at 16:19
  • Maybe just a human being helping out another human being ;-) I'm glad that you found your problem. Now it won't happen again! :-D – Dandré May 30 '16 at 06:48
  • That will do too! :P – Crystal Jun 03 '16 at 19:46