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.