10

SOAP Faults

 

We all have weaknesses, and SOAP is no exception. SOAP has certain inherent lacunae, which are termed as SOAP fault codes. In all, there are four fault codes:

     ClientFaultCode

     ServerFaultCode

     MustUndersatndCode

     VersionMismatchFaultCode.

 

In this chapter, we shall discuss these fault codes threadbare, and delve upon details such as- when and why these faults occur.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Xml;

[WebServiceBinding()]

public class zzz : WebService

{

[WebMethod()]

public void abc()

{

throw new SoapException("vijay", SoapException.ClientFaultCode);

}

}

 

a.cs

class aaa

{

public static void Main()

{

zzz a= new zzz();

try

{

a.abc();

}

catch ( System.Exception e)

{

System.Console.WriteLine(e.ToString());

}

}

}

 

z.bat

del *.exe

del *.dll

wsdl aa.wsdl

csc /t:library zzz.cs

csc a.cs /r:zzz.dll

a

 

Output

System.Web.Services.Protocols.SoapException: System.Web.Services.Protocols.SoapException: vijay

   at zzz.abc()

 

SOAP response

<soap:Body>

<soap:Fault>

  <faultcode>soap:Client</faultcode>

  <faultstring>System.Web.Services.Protocols.SoapException: vijay at zzz.abc()</faultstring>

  <detail />

  </soap:Fault>

</soap:Body>

The function abc in the asmx file, throws an exception called SoapException. The exception is generated by calling the SoapException constructor with two parameters:

     The first parameter is a message, which specifies the error that occurred.

     The second parameter reveals the type of error that occurred.

 

The second parameter can have four possible values, out of which, we have specified the value of 'ClientFaultCode'.

 

The value of ClientFaultCode represents a SOAP fault code, and not an error. It mainly signifies that the client SOAP payload is neither properly formatted, nor does it contain all the requisite data. This could occur in situations where a user id and password are expected, but are not contained in the SOAP packet. The client is also forewarned not to rebound the same packet, since it contains errors. In the client program, the exception is caught in 'e', which is an instance of the Exception class.

 

The SOAP trace depicts the SOAP response packet, which holds all the details related to the exception. The exception thrown by the asmx file is sent across the net, in the form of a SOAP fault. The Body element is followed by the Fault element, which in turn, has a child element called soap:Client. This child element reveals the exception code as ClientFaultCode.

 

The faultstring element first specifies the name of the Exception, followed by the string 'vijay', which is supplied as the first parameter to the SoapException constructor. This is followed by the class and function names that have thrown the exception.

 

a.asmx

throw new SoapException("vijay",SoapException.ServerFaultCode);

 

SOAP response

<soap:Fault>

  <faultcode>soap:Server</faultcode>

  <faultstring>

System.Web.Services.Protocols.SoapException: vijay at zzz.abc()

</faultstring>

  <detail />

  </soap:Fault>

 

The parameter value of ServerFaultCode notifies us that a fault has occurred on the server, while the SOAP payload that was sent by the client, was being processed. In this case, the error did not occur because the data carried by the SOAP packet is faulty.   In fact, the error could be attributed to any one of the myriad problems, such as- the network being down, the server being busy, et al. The client is expected to retransmit the same data, after just a short time gap.

 

The third fault code that we shall be analyzing is, the MustUndersatndCode. Since the SOAP element carries an element with an attribute of MustUnderstand set to 1, the server is unable to decipher the element on receiving it; and resultantly, it throws an error. Thus, the exception is thrown by the server, and not by the client. Under these circumstances, the client must not resend the payload, and even if it does, the MustUnderstand attribute must be set to 0.

 

The last fault code that we shall examine is VersionMismatchFaultCode, which occurs whenever an invalid namespace is sighted in the Envelope element. Using this fault code, the server sends a signal to the client, indicating that an error has occurred.

 

The Invoke function has adequate potency to distinguish between a normal packet and a Soap Fault. So, whenever it encounters a fault, it throws an exception.

 

a.asmx

throw new System.Exception("vijay");

 

SOAP response

<soap:Fault>

<faultcode>

soap:Server

</faultcode>

<faultstring>

System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.Exception: vijay at zzz.abc()

</faultstring>

<detail />

</soap:Fault>

 

In the asmx file, instead of a SoapException, it is a normal Exception that is thrown.  The .Net framework is extremely smart, in that, it converts this Exception into a SoapException, and assigns the value of ServerFaultCode to the fault Code.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Xml;

[WebServiceBinding()]

public class zzz : WebService

{

[WebMethod()]

public XmlNode abc()

{

XmlDocument d = new XmlDocument();

XmlNode n = d.CreateNode(XmlNodeType.Element,"sonal", "mukhi");

XmlNode c = d.CreateNode(XmlNodeType.Element, "vijay", "hell");

n.AppendChild(c);

XmlAttribute a = d.CreateAttribute("a1", "bad");

a.Value = "good";

c.Attributes.Append(a);

return n;

}

}

 

SOAP response

<abcResult>

<sonal xmlns="mukhi">

<vijay n1:a1="good" xmlns:n1="bad" xmlns="hell" />

</sonal>

</abcResult>

 

Many of you may consider XML to be a gobbledy-gook or a mere verbiage! Hence, we have taken a slight detour into the realm of the XmlNode class.

In this program, we start by creating an empty XmlDocument object 'd', and then, utilizing the CreateNode function, we create an element called 'sonal', within the namespace called 'mukhi'.

 

The first parameter of the CreateNode function specifies the type of entity that must be created. The last parameter to this function refers to the namespace that the entity generates. This function then returns an XmlNode object, which is stored in the object n.

 

Thereafter, another node named 'c', containing the element 'vijay' in the namespace 'hell', is created. Since we want this element to be the child of the element 'sonal', the AppendChild function of node 'n' is used, with the parameter of 'c'.

 

Then, the CreateAttribute function is used to associate attributes to the elements. This function creates an attribute a1, and places it in the n1 namespace. It is for this reason that the attribute a1 has a prefix n1, pointing to the uri named 'bad', which is our second parameter. Every attribute requires a value. Therefore, the Value property of the attribute class is initialized to the specific value of 'good'.

 

Finally, to associate this property with the node c, the collection property named Attributes is used. The Append function of this collection adds the attribute.  Since the return value of the function abc is specified as 'n', the abcResult element in the SOAP element displays the entire XmlNode.

 

a.asmx

<%@ WebService Language="C#" Class="zzz" %>

using System.Web.Services;

using System.Web.Services.Protocols;

using System.Xml;

[WebServiceBinding()]

public class zzz : WebService

{

[WebMethod()]

public void abc()

{

XmlDocument d = new XmlDocument();

XmlNode n = d.CreateNode(XmlNodeType.Element,"sonal", "mukhi");

XmlNode c = d.CreateNode(XmlNodeType.Element, "vijay", "hell");

n.AppendChild(c);

XmlAttribute a = d.CreateAttribute("a1", "bad");

a.Value = "good";

c.Attributes.Append(a);

XmlDocument d1 = new XmlDocument();

XmlNode n1 = d1.CreateNode(XmlNodeType.Element,"sonal1", "mukhi1");

XmlNode c1 = d1.CreateNode(XmlNodeType.Element, "vijay3" , "");

n1.AppendChild(c1);

XmlDocument d2 = new XmlDocument();

XmlNode n2 = d2.CreateNode(XmlNodeType.Element,"sonal2", "mukhi2");

XmlNode [] m = new XmlNode[2];

m[0] = n1;

m[1] = n2;

System.Exception e = new System.Exception("haha");

throw new SoapException("vijay",SoapException.ServerFaultCode ,"sonal", n , m , e);

}

}

 

SOAP response

<soap:Body>

- <soap:Fault>

  <faultcode>soap:Server</faultcode>

<faultstring>System.Web.Services.Protocols.SoapException: vijay ---> System.Exception: haha at zzz.abc()</faultstring>

  <faultactor>sonal</faultactor>

- <sonal xmlns="mukhi">

  <vijay n1:a1="good" xmlns:n1="bad" xmlns="hell" />

  </sonal>

- <sonal1 xmlns="mukhi1">

  <vijay3 xmlns="" />

  </sonal1>

  <sonal2 xmlns="mukhi2" />

  </soap:Fault>

</soap:Body>

 

Using the same analogy, we first create a simple XmlNode named 'n'. Thereafter, we create two more XmlNodes named 'n1' and 'n2'. One child node is added to the node n1, whereas, no child nodes are appended to the node n2. Once this is done, an array of XmlNodes named 'm', with a size of 2 is created, and  its two members are initialised to n1 and n2, respectively.

 

The SoapException that gets thrown at this stage, has six parameters:

     The first parameter that contains the value of 'vijay', is the name of the message, which eventually gets converted to the fault string.

     The second parameter is the fault code named SoapException.ServerFaultCode.

     The third parameter is the Actor. The element is called 'faultactor', and the value assigned is 'sonal'. The actor is the cause of the fault. Normally, it should contain the line number or some other information, which helps in identifying the error.

     The fourth parameter is the XmlNode object. This object must contain the detailed specifics of the error that occurred. Here, the actual lines of code or variables that caused the error, may be specified. Since an XmlNode is required, supplying an entire formatted XML document would also suffice.

     The fifth parameter is an array of XmlNodes, which can be initialized to any content that we desire.  Normally, the contents of the body element are embodied in the parameters discussed so far. However, for this parameter, the specifics not related to the body, are laid down. Thus, we encounter 'sonal1' and 'sonal2' at the end of the Body element. The 'detail' tag is missing at this stage.

     The sixth parameter is the Exception, whose constructor value gets merged into the fault string.

 

a.cs

class aaa

{

public static void Main()

{

zzz a= new zzz();

try

{

a.abc();

}

catch ( System.Web.Services.Protocols.SoapException e)

{

System.Console.WriteLine(e.Actor);

System.Console.WriteLine(e.Code);

if ( e.Detail == null)

System.Console.WriteLine("Detail is null");

System.Console.WriteLine(e.OtherElements[0].InnerXml);

System.Console.WriteLine(e.OtherElements[1].InnerXml);

System.Console.WriteLine(e.ToString());

}

}

}

 

Output

sonal

http://schemas.xmlsoap.org/soap/envelope/:Server

Detail is null

<vijay n1:a1="good" xmlns:n1="bad" xmlns="hell" />

<vijay3 xmlns="" />

System.Web.Services.Protocols.SoapHeaderException: System.Web.Services.Protocols.SoapException: vijay ---> System.Exception: haha

   at zzz.abc()

 

The asmx file remains unaltered for this program. Here, we have attempted to display all the members of the SoapException object 'e'. The 'Actor' property displays the value of 'sonal', followed by the Fault code member Code. The value of Code is not merely 'Server', but is preceded by a lengthy URI and a colon.

 

This evinces the fact that the SOAP Fault payload content is copied into properties, such as Actor, by the Invoke function. However, for reasons unknown to us, the 'detail' property does not get filled up at all. Since the 'if' statement is true, the value of the property is not displayed; instead, a text string is displayed.

 

The OtherElements property is an array of 2 XmlNodes. Thus, we use the InnerXml property to display the entire node, using an index element. As was the case earlier, the Exception carries the strings of 'vijay' and 'haha'. Thus, all the data that we enclose and dispatch in the Exception, is made available to the client.

 

a.asmx

throw new SoapHeaderException("vijay",SoapException.ServerFaultCode ,"sonal", m , e);

 

SOAP response

<soap:Fault>

<faultcode>soap:Server</faultcode>

<faultstring>System.Web.Services.Protocols.SoapHeaderException: vijay ---> System.Exception: haha at zzz.abc()</faultstring>

</soap:Fault>

 

Whenever an Exception occurs within the SOAP headers, a SoapHeaderException should be thrown. Everything remains unchanged, but for the Exception name, which gets altered. Also, the SOAP response displays the changes from SoapException to SoapHeaderException in the Exception.