Hello,

Thanks everyone for the helpful responses.

Although it would be possible to create a wrapper class, I'd really
rather not given that I think it should be easy to check for the fault
in the C# client.  If the client was a third-party application in
which I had absolutely no control, that would be a different matter.

What I would like to do is find some happy medium that works well with
an XFire service and C# clients.  Here's what I found so far using an
XFire Aegis mapped service and by writing my own C# client:

* Throwing a checked exception (that's specified in your service
interface) causes XFire to generate a SOAP fault where the faultcode
== "soap:Server" and faultstring contains the exception text message.

* In C#, a SOAP fault from XFire translates into a SoapException where:
 - SoapException.Message contains the message text specified to the
Java Exception.
 - SoapException.Code.Name contains the faultcode "Server" (soap: is
stripped off)
 - SoapException.Details.FirstChild.Name is the name of the Java
Exception, i.e. "RecordNotFoundException".

Although it's trivial for the C# application to check the exception
message, I'd rather specify a meaningful code that's easy to check.
Right now, the faultcode shows up as:
   <faultcode>soap:Server</faultcode>
which provides no indication of the problem.  I'd like to change it to
something like:
   <faultcode>soap:Server.RecordNotFound</faultcode>
as from what I've read in the SOAP specs, this is how error codes can
be specified (http://www.w3.org/TR/2000/NOTE-SOAP-20000508/#_Toc478383510).

So my question now is, how do I specify my own error code for the SOAP
fault code?

Well, that was my question.  It turned out to by very easy to
customize the fault code--just have my exception class extend
XFireFault instead of something else and then specify the fault code
in a QName.  My Exception class now looks like this:

public class RecordNotFoundException extends XFireFault {
   public RecordNotFoundException() {
       super();
   }
   public RecordNotFoundException(String message) {
       super(message, new QName(null, "soap:Server.RecordNotFound"));
   }
}

The service interface is:
public interface PersonService {
   public Person findByLoginId(String id) throws RecordNotFoundException;
}

which generates (slightly abbreviated):
     <soap:Fault>
        <faultcode>soap:Server.RecordNotFound</faultcode>
        <faultstring>No record with id 123100782F was found by the
findByLoginId method!</faultstring>
     </soap:Fault>

which is exactly what I wanted.

The C# SOAP fault checking is now very easy:
try {
   person = personService.findByLoginId("123100782F");
} catch (System.Web.Services.Protocols.SoapException se) {
   if (!se.Code.IsEmpty && se.Code.Name.Equals("Server.RecordNotFound")) {
       Console.WriteLine("Record was not found: " + se.Message);
   }
}

Thanks!
-Bill

On 11/22/06, Tomek Sztelak <[EMAIL PROTECTED]> wrote:
Hi

On 11/21/06, Bill Burton <[EMAIL PROTECTED]> wrote:
> Hello,
>
> I've written a simple service that provides a way to lookup Person objects
> by id or email address. The Person object just has some name and address
> information. When a record is not found, I'm catching the runtime exception
> from the Spring JDBC API, and rethrowing a checked exception which causes
> XFire to generate a SOAP fault as follows:
>
> <soap:Envelope
> xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/";
> xmlns:xsd="http://www.w3.org/2001/XMLSchema "
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";>
>    <soap:Body>
>       <soap:Fault>
>          <faultcode>soap:Server</faultcode>
>          <faultstring>No record with id 000123005 was found by the findById
> method!</faultstring>
>          <detail>
>             <RecordNotFoundException xmlns=" http://webservice.teds.pms"/>
>          </detail>
>       </soap:Fault>
>    </soap:Body>
> </soap:Envelope>
>
> Right now, I'm just using the default generated bindings in my Spring
> applicationContext.xml
>
>     <bean name="PersonService"
> class="org.codehaus.xfire.spring.ServiceBean">
>         <property name="serviceBean" ref="PersonServiceImpl"/>
>         <property name="serviceClass"
> value="pms.teds.webservice.PersonService"/>
>     </bean>
>
> but plan to switch to Aegis to have better control over the mapping for
> other reasons.

Aegis is a default binding, so you are already using it:)

> However, the person who's writing a C# .NET client to handle this complains
> that it's hard to check for a fault whereas if I were to return an error
> code and error text in my Person object, he would have no problem.  As the
> Person object is supposed to be a reflection of the database columns, I
> really don't want to change it in this manner.
>
> What are the best practices for generating an error such as "record not
> found" or "database not available" cases?

I think that adding error codes to your data model object is a bad
idea. You should use exception ( SOAP fault ), as you do now.

> Thanks for any assistance,
> -Bill
> --
> Bill Burton < bburton ayht mail daht com>
>

---------------------------------------------------------------------
To unsubscribe from this list please visit:

   http://xircles.codehaus.org/manage_email

Reply via email to