When building an Indigo based service, you might need to signal an error to your clients.
Normally, one would expect to be able do this normally by simply throwing an exception from a service method, just like in ASP.NET. However, this doesn't seem to be the case with Indigo: all I'm seeing happening is the client hanging and getting no response at all from the server, and then failing with a closed connection. I would've expected at least an HTTP 500 error back, or something telling me that something bad happened during the request execution, but no dice.
I did notice, however, that during development you can enable an option instructing Indigo to serialize the exception messages as strings and put those into the returned soap fault, allowing you to get some extra details on the exception on the client side. To do this, you can enable the ReturnUnknownExceptionsAsFaults behavior on the service, either by code or by configuration file. Here's an example of the former:
[ ServiceBehavior(ReturnUnknownExceptionsAsFaults=true) ]
public class ...
With this option enabled, exceptions are returned to the client correctly, arriving as exceptions of the System.ServiceModel.UnknownFault class. One thing to notice when using this attribute is that you need to apply it to the service implementation class, not the service interface definition, so watch out for that.
Real Faults
This is all well and good, but not very useful by itself. In most cases, you'll want a stronger contract than some error string lying around in your faults. If you need to provide detailed and useful error information to your clients in a way that they can access it easily, you'll want to make sure your service returns a custom XML fragment inside the
Indigo provides an easy way to do this by returning custom faults from your operations instead of simple exceptions. To do this, you can create a DataContract class that represents your fault's details, and then, inside your methods, throw an instace of the Fault
[DataContract]
public class InvalidNameFault
{
[DataMember]
public string Description;
[DataMember]
public string NameUsed;
}
[ServiceContract]
public interface IFaultyService
{
[OperationContract]
[FaultContract(typeof(InvalidNameFault))]
string Hello(string name);
} // interface IFaultyService
public class FaultyService : IFaultyService
{
public string Hello(string name)
{
// fault if name contains "Tomas"
if ( name.IndexOf("Tomas") >= 0 ) {
InvalidNameFault details = new InvalidNameFault();
details.NameUsed = name;
details.Description =
"An unrecognized name was passed to the service";
throw new Fault(details);
}
return "Hello " + name;
}
}
As you can see, I just defined a custom class to carry the fault information as a DataContract (InvalidNameFault), which contains a couple of data members serialized as part of the fault. Also, notice that inside the implementation of the Hello() method, we just create an instance of the InvalidNameFault class, fill it out, and then wrap it in an instance of the Fault
On the client side, if we're building with Indigo, a nice thing is that we can catch an instance of the typed Fault class and easily access the information serialized into the Fault Details:
FaultyServiceProxy proxy =
new FaultyServiceProxy(epa, binding);
try {
string hello = proxy.Hello("Tomas Restrepo");
Console.WriteLine(hello);
} catch ( Fault e ) {
Console.WriteLine("{0}: {1}", e.Detail.Description, e.Detail.NameUsed);
}
The most interesting thing of this whole thing is that Indigo can make your custom faults part of the service contract. Notice how I use the [FaultContract] attribute in the operation declaration, telling Indigo that a possible fault returned by my service contains custom information in the form of the InvalidNameFault contract. What's really cool about this is that this information will actually surface as part of the service description in the WSDL:
http://localhost:8188/FaultyService
Indigo will also generate the custom WSDL necessary for the custom fault class: