I have a WCF service that if something goes wrong throws a generic FaultException. I don't know why, sometimes the clients will catch a non-generic FaultException instead of the generic exception.
Does anybody know, what the problem is?
I have a WCF service that if something goes wrong throws a generic FaultException. I don't know why, sometimes the clients will catch a non-generic FaultException instead of the generic exception.
Does anybody know, what the problem is?
Your service needs to handle all exceptions and wrap them into FaultException<T> where T is a data contract you have written. So the first step is to define a custom data contract that will contain your exception information:
[DataContract]
public class CustomFault
{
public string Message { get; set; }
}
Then you instruct your service contract that its methods could potentially throw FaultException<CustomFault>. This allows the service to expose the CustomFault class in the wsdl, so that clients could generate a proxy class:
[ServiceContract]
public interface IMyServiceContract
{
[FaultContract(typeof(CustomFault))]
void MyMethod(string someArgument);
}
Next step is to implement this interface:
public class MyService : IMyServiceContract
{
public void MyMethod(string someArgument)
{
// Do something here that could throw exceptions but don't catch yet
}
}
To handle exceptions you could implement IErrorHandler which will be used whenever one of your service methods throws an exception. The purpose of this error handler is to wrap the exception into FaultException<CustomFault>:
public class MyErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message msg)
{
var customFault = new CustomFault()
{
Message = error.Message,
};
var fe = new FaultException<CustomFault>(customFault);
MessageFault fault = fe.CreateMessageFault();
string ns = "http://somenamespace/whatever";
msg = Message.CreateMessage(version, fault, ns);
}
}
Once you have registered your error handler, on the client side, you will always get FaultException<CustomFault>.
If your client doesn't have access to the Exception type itself (the < T> on FaultException< T>) then the non-generic version of the FaultException is thrown. I just spent hours trying to figure this out, and eventually realized it when I found this on the msdn forums. It would be great if there was some indication that the exception was changed before throwing it out of the service, but there isn't.
The non-generic FaultException
is thrown when the service throws some other exception that is not caught. You'll need to find out what the exception is and fix it if it's a bug, or else decide it's something you want to expose your clients to, then wrap it in a generic FaultException
and add a FaultContract
appropriately.
another possibility is that your TDetail is not being serialized properly. This may be the case if e.g. TDetail derives from Exception and you have an inner exception that is not serializable.
This will happen if you have not declared your fault detail type with a FaultContractAttribute.
Here is how your service contract should look:
[ServiceContract]
public interface IMyServiceContract
{
//...
[OperationContract]
[FaultContract(typeof(MyFaultDetail))]
[FaultContract(typeof(OtherFaultDetail))]
GetDetailsResp GetDetails(GetDetailsReq req);
//...
}
I was seeing the same issue and the link Drew posted provided the answer for me.
The resolution for me was that my Service Interface had a different Namespace than my Service fault.
ie, the service contract had:
[ServiceContract(Namespace = "http://dummydomain.com/service/searchservice")]
public interface ISearchService
....
and the service fault had:
[DataContract(Namespace = "http://dummydomain.com/service/searchservicefault")]
public class MySearchServiceFault
...
apparently when the namespaces are different the client doesn't know what to do with it and reverts back to the non generic FaultContract... I think this depends somewhat on the client as I have seen the above code work and return the generic FaultContract...
But, when I changed the namespaces to be the same it seems to make the code work all the time in my testing.
I had a similar issue, and it happened when I upgraded some NuGet packages, used a shared .NET standard class, etc (I don't know exactly what caused it, a lot of changes happened over two months, but these were among the changes). It turned out to be an issue where the Action was set to the string "FAULT" before, and it worked fine client-side with the default FaultContract attributes. But after these changes (late 2018) the string "FAULT" as action meant that it didn't match the fault classes any more and I got the general FaultException instead. The change that fixed it all (no changes client-side) was to set the action to "null" when throwing the FaultException instead of "FAULT". I figured I'd just post that fix here as an answer if anybody else is running into this.