views:

513

answers:

4

I need to design a SOAP api (my first one!). What are the best practices regarding errors returned to the caller.

Assuming an api as follow

[WebMethod]
public List<someClass> GetList(String param1)
{
}

Should I

  • Throw an exception. Let the SOAP infrastructure generate a SOAP fault -- and the caller would have to try/catch. This is not very explanatory to the caller
  • Have the return parameter be a XMLDOcument of some sort, with the first element being a return value and then the List.
  • Looking at the return SOAP packet I see that the response generated looks like the following
 <GetListResponse>
   <GetListResult>
     ...
     ...   
 </GetListResult>
</GetListResponse>

Can we somehow change the return packet so that the "GetListResult" element is changed to "GetListError" in case of error

  • Any other way?

Thanks!

+2  A: 

Probably the most appropriate SOA pattern to follow would be a Fault Contract, which is essentially a Data Contract that is wrapped in the SOAPException.

I am posting examples in .NET, since it looks like that is what you are using (and that is what I know :) )

In WCF, you can define a DataContract, then decorate your OperationContract interface with a a "FaultContract" attribute that specifies it as the return value:

public partial interface MyServiceContract
{
    [System.ServiceModel.FaultContract(typeof(MyService.FaultContracts.ErrorMessageFaultContract))]
    [System.ServiceModel.OperationContract(...)]
    ResponseMessage SOAMethod(RequestMessage request) {...}
}

For ASMX web services, (as it appears you are using from your code snippet), you can't use this attribute or setup. So to implement the pattern, you would need to:

  • Define a serializable class to hold your exception information (i.e. ErrorData)
  • When an exception is thrown in your service, catch it and in your error handling code, add the info to the ErrorData class
  • Append the serialized ErrorData class to a SoapException class:

    SoapException mySoapException = new SoapException(message, SoapException.ServerFaultCode, "", serialzedErrorDataClass);
    
  • Throw the SoapException in your code

  • On your client side, you will need to deserialize the message to interpret it.

Kind of seems like a lot of work, but this way you have total control of what data gets returned. Incidentally, this is the pattern that is used by the ServiceFactory from Microsoft patterns & practices for ASMX web services.

Guy Starbuck
+1  A: 

There is some good information on Coding Horror.

Jeremy Stein
A: 

I can't give you specifies for .net (which seems to be what you're asking), but SOAP provides a mechanism for expressing strongly-typed exceptions. The SOAP fault element can have an optional FaultDetail sub-element, and this can contain arbitrary XML documents, such as your GetListError. These document types should be defined in the WSDL as a wsdl:fault inside the wsdl:operation

The trick is persuading the web service stack to turn an exception (which is the "correct" way of writing your business logic) into a properly marshalled fault detail. And I can't help you with that bit.

skaffman
+1  A: 

You can cause the correct fault to be returned from old ASMX services, but it's not easy. First of all, you'll have to hand-code the WSDL, because the ASMX infrastructure will never create Fault elements in a WSDL. Then, you have to serialize the desired fault data into an XmlElement that you will then provide as the Detail property of the SoapException that you will throw.

It's much easier with WCF. You can declare a number of FaultContracts for each operation, and WCF will generate the correct WSDL to refer to them. You then simply throw a FaultException, where type T is the type of the FaultContract. Pass the T instance to the constructor, and you're all set.

John Saunders