I have a camel-cxf webservice up. I use to handle all SOAP Faults in the CXF's SOAP Fault Interceptor mechanism. That is working well.
I thought that its better to handle Exception thrown at the Camel layer at the same layer and wrote a simple onException scenario like this:
onException(Exception.class).
to("direct:MyWSExceptionHandler");
Whenever a custom exception is thrown, I was expecting the onException to kick in(Remember I also have a SOAP Fault Interceptor too), but it doesn't. The CXF is taking over and the message is going through the Interceptors, rather than the Camel Route.
Is this the expected way, or am I doing something wrong?
My CXF fault interceptor looks like this:
#Component("SOAPFaultInterceptor")
public class SOAPFaultInterceptor extends AbstractPhaseInterceptor {
public SOAPFaultInterceptor() {
super(Phase.MARSHAL);
}
public void handleMessage(Message message) throws Fault {
// The message is coming here directly, instead of going to the route defined by onException.
}
}
Can someone please tell how to fix this? I don't want Exception generated at the Camel layer to leave that layer without being handled..
Thanks in advance.
Camel's onException only triggeres if there is an exception. A SOAP Fault is represented as a Message with the fault flag = true.
What you can do is to set handleFault=true on CamelContext, then it will turn SOAP fault messages into an exception that the onException can react upon.
Related
I have a workflow service. I also use workflow persistence in that service. But after I deployed workflow in IIS, from client I make a request to workflow service, in log file on server. I see a message
The execution of the InstancePersistenceCommand named {urn:schemas-microsoft-com:System.Activities.Persistence/command}SaveWorkflow was interrupted by an error.InnerException Message: Type 'System.ServiceModel.Channels.ReceivedFault' cannot be serialized.
Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.
If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
I tried research about this exception, but I didn't find anything.
How to fix this problem ? or let me know what is the reason about above exception ?
System.ServiceModel.Channels.ReceivedFault is a non-serializable internal .NET framework class, so unfortunately there is nothing you can do to correct the actual root cause (i.e. making said class serializable).
You are probably calling an external service via WCF which faults, i.e. a System.ServiceModel.FaultException is thrown. IIRC, somewhere deep down in that FaultException object is a reference to the culprit, a ReceivedFault instance.
Solution: Catch all FaultExceptions, transfer the information you need to know from the FaultException into a serializable exception, and throw the latter:
try
{
CallService();
}
catch (FaultException ex)
{
// Gather all info you need from the FaultException
// and transport it in a serializable exception type.
// I'm just using Exception and the message as an example.
throw new Exception(ex.Message);
}
In my WCF service I have implemented a custom encoder which inherits from System.ServiceModel.Channels.MessageEncoder.
In that encoder, I take the raw message and manipulate the received headers in my override of the ReadMessage() method.
During this manipulation, I may sometimes detect something in the header which makes the message invalid, and I want to return a useful exception to the client.
I have tried:
throw new Exception("Some useful message");
And:
throw new FaultException("Some useful message");
They both return an HTTP 400 to the client with no response body.
I can happily throw a FaultException from my actual web service method and this is returned to the client correctly, but at that late stage of the processing I no longer have access to the SOAP headers (unless someone can tell me otherwise).
How can I return a response 500 to the client with a friendly message based on information in the SOAP header?
You can call:
OperationContext.Current.IncomingMessageHeaders
in your service method to inspect the headers there if you wish. A custom MessageEncoder seems to me the wrong beast to be using to do what you describe.
I am trying to catch the ValidationFault exceptions of my service and return a instance of MyClass with the property Message filled with the validation error provided by EntLib when my client calls one of my service methods without the correct parameters (I can't use complex types).
I tried to implement two interfaces to accomplish this task: IParameterInspector and IOperationInvoker. The problem is after the method BeforeCall is called (of the IParameterInspector interface), EntLib throws the ValidationFault exception but I can't catch it and my code doesn't reach the Invoke method of my IOperationInvoker class and because of that I can't replace the return value with a instance of MyClass.
Remember, my client is not based on .NET platform and there's no such thing as catch(FaultException<ValidationFault> ex) there. That's why I MUST work with a default object on my service responses.
I appreciate the help.
Can you use an IErrorHandler implementation similar to Enterprise Library's WCF ExceptionShielding? Basically catch all exceptions and if it's a FaultException<ValidationFault> then convert the ValidationFault to your custom message and return it.
It looks like the output of ProvideFault is a Message so you could return a message instead of a fault. This posting seems to give the approach.
I understand that WCF will convert an exception into a fault and send it back as a SOAP message, but I was wondering if this is truly interoperable. I guess I'm having a tough time trying to figure out this possible scenario:
Client (Java) calls a WCF Service
(LoginService).
Server checks for proper authorization, user authorization fails.
Server throws an UnauthorizedAccessException.
WCF converts this into a Fault somehow. (* - See Below As Well)
Client has to be able to know how to read this Fault.
I guess I'm just having a tough time understanding how this could still be interoperable because it is expecting Java to know how to translate a SOAP Fault that .NET encodes from an UnauthorizedAccessException.
Also, how does .NET actually convert the exception to a fault, what goes in as the fault code, name, etc. Some of the things seem to be "duh"s like perhaps the Fault Name is "UnauthorizedAccessException", but I'd rather know for sure than guess.
There is no "automatic conversion". WCF will return a fault (I forget which one) when you have an unhandled exception. But since you didn't declare that fault, many, if not most, clients will fail if you return it.
You are meant to define your own faults and to return them instead. Consider:
[DataContract]
public class MySpecialFault
{
public string MyMessage { get; set; }
}
[ServiceContract]
public interface IMyService
{
[FaultContract(typeof (MySpecialFault))]
[OperationContract]
void MyOperation();
}
public class MyService : IMyService
{
public void MyOperation()
{
try
{
// Do something interesting
}
catch (SomeExpectedException ex)
{
throw new FaultException<MySpecialFault>(
new MySpecialFault {MyMessage = String.Format("Sorry, but {0}", ex.Message)});
}
}
}
Any client capable of handling faults will deal with this. The WSDL will define the fault, and they will see a fault with the Detail element containing a serialized version of the MySpecialFault instance that was sent. They'll be able to read all the properties of that instance.
Faults have been part of the SOAP specification since v1.1. They are explained in the SOAP Specification.
It is up to implementations (WCF, Java etc) to ensure that Faults are handled according to the specification.
Since WCF converts FaultExceptions to Faults according to the SOAP specification, FaultExceptions thrown from WCF are interoperable.
SOAP faults are interoperable but .Net exception classes are not good to be used in SOAP faults. Instead define your own DataContract class (e.g. AccessFault) and then use it in a FaultContract.
see http://msdn.microsoft.com/en-us/library/ms733841.aspx
Whenever there is a UnauthorizedAccessException thrown at service boundary convert it to FaultException.
This can be done in several ways like using Microsoft Enterprise Library Exception Handling Block or implementing the IErrorHandler interface.
I have a WCF service deployed on two or more remote machines and there is a desktop based application that is used by the client to access any wcf service.
The WCF service is connected to SQL server 2005 to read and write data.
This is an intranet scenario in which the client should be on same domain.
Now there can be scenarios where the wcf service throws exceptions:
Invalid URL
WCF service is down
SQL server 2005 is not running
Client is not on the same domain
Authentication fails
Authorization fails
and many other exceptions.
For every exception I have to perform some action or update a status bar, depending on the exception. For example if authorization fails I have to prompt the user to re-enter their credentials.
Please suggest the best design approach to handle this.
You can definitely catch and handle all exceptions that happen on your service class and turn them into a FaultException or FaultException exception.
That way, you won't "fault" (or tear down) the communications channel between your client and server.
Even better approach would be to implement the IErrorHandler interface on your service class that provides a way to globally catch all exceptions as they happen and provide a FaultException instead, that's SOAP compliant.
You can even turn your IErrorHandler into a configurable behavior that can be turned on or off in config.
See these articles and blog posts for more details:
Rory Primrose: Implementing IErrorHandler
Useful WCF behaviors: IErrorHandler
Create a custom fault class that is marked with the DataContract attribute
Mark the method on the service contract interface with FaultContract. Ie. [FaultContract(typeof(CustomFault))]
In your service method, catch any applicable internal exceptions and throw a FaultException<CustomFault>. Alternatively, as marc_s mentioned, you can use IErrorHandler to map the exception to the fault.
Personally, I create a base Fault class that has a Reason property and I extend all custom faults from this class. When I want to throw the fault, I call:
throw Fault.Create<CustomFault>(new CustomFault("Boo hoo"));
It's also worth noting that I version my fault classes (including the common Fault class) along with all my other services. This is only a concern if service versioning is a concern, though.
Here's the basic Fault class (I've removed argument validation for brevity):
[DataContract(Namespace = XmlVersionNamespace.FaultNamespace)]
public abstract class Fault
{
internal FaultReason Reason { get; set; }
protected Fault(string reasonText)
{
Reason = new FaultReason(new FaultReasonText(reasonText, CultureInfo.CurrentUICulture));
}
public override string ToString()
{
return Reason.ToString();
}
internal static FaultException<TDetail> Create<TDetail>(TDetail fault) where TDetail : Fault
{
return new FaultException<TDetail>(fault, fault.Reason);
}
}
You can design the specific Fault Data Contracts for each of the exception scenario in your WCF service so that you can handle the fault/exception at client side respectively.
try
{
// Actions
}
catch (Exception ex)
{
// Log the exception
// Throw Fault Exception back to client
FaultException fe = new FaultException(ex.Message, new FaultCode("Your fault code"));
//throw fault exception back to WCF client
throw fe;
}